代码之家  ›  专栏  ›  技术社区  ›  Craig

XSLT concat字符串,删除最后一个逗号

  •  29
  • Craig  · 技术社区  · 17 年前

    我需要使用XSLT构建一个字符串,并用逗号分隔每个字符串,但不要在最后一个字符串后包含逗号。在我下面的示例中,如果我有分发节点而不是Note节点,那么后面会有一个逗号。我不知道如何构建一个字符串作为变量,然后截断XSLT中的最后一个字符。这也是使用MicrosoftXSLT引擎。

    我的绳子=

    <xsl:if test="Locality != ''">
      <xsl:value-of select="Locality"/>,
    </xsl:if>
    <xsl:if test="CollectorAndNumber != ''">
      <xsl:value-of select="CollectorAndNumber"/>,
    </xsl:if>
    <xsl:if test="Institution != ''">
      <xsl:value-of select="Institution"/>,
    </xsl:if>
    <xsl:if test="Distribution != ''">
      <xsl:value-of select="Distribution"/>,
    </xsl:if>
    <xsl:if test="Note != ''">
      <xsl:value-of select="Note"/>
    </xsl:if>
    

    [老兄,一定有更好的方法进入这个问题文本框:(]

    6 回复  |  直到 10 年前
        1
  •  52
  •   Jay    12 年前

    使用XSLT很容易做到这一点 不需要在变量中捕获结果,也不需要使用特殊的命名模板

    :

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
    
        <xsl:template match="/*/*">
          <xsl:for-each select=
          "Locality/text() | CollectorAndNumber/text()
         | Institution/text() | Distribution/text()
         | Note/text()
          "
          >
            <xsl:value-of select="."/>
            <xsl:if test="not(position() = last())">,</xsl:if>
          </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>
    

    <root>
        <record>
            <Locality>Locality</Locality>
            <CollectorAndNumber>CollectorAndNumber</CollectorAndNumber>
            <Institution>Institution</Institution>
            <Distribution>Distribution</Distribution>
            <Note></Note>
            <OtherStuff>Unimportant</OtherStuff>
        </record>
    </root>
    

    产生了想要的结果

    Locality,CollectorAndNumber,Institution,Distribution
    

    如果需要的元素不按文档顺序生成

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="text"/>
    
        <xsl:param name="porderedNames"
         select="' CollectorAndNumber Locality Distribution Institution Note '"/>
    
        <xsl:template match="/*/*">
            <xsl:for-each select=
             "*[contains($porderedNames, concat(' ',name(), ' '))]">
    
             <xsl:sort data-type="number"
              select="string-length(
                         substring-before($porderedNames,
                                          concat(' ',name(), ' ')
                                          )
                                    )"/>
    
                <xsl:value-of select="."/>
                <xsl:if test="not(position() = last())">,</xsl:if>
            </xsl:for-each>
        </xsl:template>
    </xsl:stylesheet>
    

    这里,字符串参数中提供了所需元素的名称及其所需顺序 $porderedNames ,其中包含以空格分隔的所有通缉犯姓名列表 .

    当上述转换应用于同一个XML文档时,就会产生所需的结果 :

    CollectorAndNumber,Locality,Distribution,Institution
    

    二,。XSLT2.0

    同样,不需要特殊功能 ):

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
    
        <xsl:template match="/*/*">
        <xsl:value-of separator="," select=
        "(Locality, CollectorAndNumber,
         Institution, Distribution,
         Note)[text()]" />
        </xsl:template>
    </xsl:stylesheet>
    

    :

    地点、收藏者和数量、机构、分布
    

        2
  •  7
  •   Dirk Vollmar    17 年前

    我更喜欢使用短调用模板将节点值连接在一起。如果连接列表中间有一个节点,也可以这样工作。 Institution ,则缺少:

    <xsl:template name="join">
        <xsl:param name="list" />
        <xsl:param name="separator"/>
    
        <xsl:for-each select="$list">
            <xsl:value-of select="." />
            <xsl:if test="position() != last()">
                <xsl:value-of select="$separator" />
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    

    输入文档示例:

    <?xml version="1.0" encoding="utf-8"?>
    <items>
      <item>
        <Locality>locality1</Locality>
        <CollectorAndNumber>collectorAndNumber1</CollectorAndNumber>
        <Distribution>distribution1</Distribution>
        <Note>note1</Note>
      </item>
      <item>
        <Locality>locality2</Locality>
        <CollectorAndNumber>collectorAndNumber2</CollectorAndNumber>
        <Institution>institution2</Institution>
        <Distribution>distribution2</Distribution>
        <Note>note2</Note>
      </item>
      <item>
        <Locality>locality3</Locality>
        <CollectorAndNumber>collectorAndNumber3</CollectorAndNumber>
        <Institution>institution3</Institution>
        <Distribution>distribution3</Distribution>
      </item>
    </items>
    

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="/">
        <summary>
          <xsl:apply-templates />
        </summary>
      </xsl:template>
    
      <xsl:template match="item">
        <item>
          <xsl:call-template name="join">
            <xsl:with-param name="list" select="Locality | CollectorAndNumber | Institution | Distribution | Note" />
            <xsl:with-param name="separator" select="','" />
          </xsl:call-template>
        </item>
      </xsl:template>
    
      <xsl:template name="join">
        <xsl:param name="list" />
        <xsl:param name="separator"/>
    
        <xsl:for-each select="$list">
          <xsl:value-of select="." />
          <xsl:if test="position() != last()">
            <xsl:value-of select="$separator" />
          </xsl:if>
        </xsl:for-each>
      </xsl:template>
    </xsl:stylesheet>
    

    生成的输出文档:

    <?xml version="1.0" encoding="utf-8"?>
    <summary>
      <item>locality1,collectorAndNumber1,distribution1,note1</item>
      <item>locality2,collectorAndNumber2,institution2,distribution2,note2</item>
      <item>locality3,collectorAndNumber3,institution3,distribution3</item>
    </summary>
    

    注意:如果您使用的是XSLT/XPath2.0,那么 fn:string-join

    fn:string-join**($operand1 as string*, $operand2 as string*) as string
    

    可按如下方式使用:

    fn:string-join({Locality, CollectorAndNumber, Distribution, Note}, ",") 
    
        3
  •  3
  •   Tomalak    17 年前

    <root>
      <record>
        <Locality>Locality</Locality>
        <CollectorAndNumber>CollectorAndNumber</CollectorAndNumber>
        <Institution>Institution</Institution>
        <Distribution>Distribution</Distribution>
        <Note>Note</Note>
        <OtherStuff>Unimportant</OtherStuff>
      </record>
    </root>
    

    然后此模板将执行以下操作:

    <xsl:stylesheet
        version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >
    
      <xsl:output method="text" />
    
      <xsl:template match="record">
        <xsl:variable name="values">
          <xsl:apply-templates mode="concat" select="Locality" />
          <xsl:apply-templates mode="concat" select="CollectorAndNumber" />
          <xsl:apply-templates mode="concat" select="Institution" />
          <xsl:apply-templates mode="concat" select="Distribution" />
          <xsl:apply-templates mode="concat" select="Note" />
        </xsl:variable>
    
        <xsl:value-of select="substring($values, 1, string-length($values) - 1)" />
        <xsl:value-of select="'&#10;'" /><!-- LF -->
      </xsl:template>
    
      <xsl:template match="Locality | CollectorAndNumber | Institution | Distribution | Note" mode="concat">
        <xsl:value-of select="." />
        <xsl:text>,</xsl:text>
      </xsl:template>
    
    </xsl:stylesheet>
    

    Locality,CollectorAndNumber,Institution,Distribution,Note
    
        4
  •  2
  •   Mostafa    14 年前

    我想有必要提一下, 当我使用复杂的select时,position()不能正常工作 过滤一些节点, 在这种情况下,我想出了以下窍门:

    您可以创建一个完整的节点列表,该位置可以很好地使用它。

    大概是这样的:

    <!-- Since position() doesn't work as expected(returning node position of current 
    node list), I got round it by a string variable and tokenizing it in which 
    absolute position is equal to relative(context) position. -->
    <xsl:variable name="measObjLdns" >
        <xsl:for-each select="h:measValue[@measObjLdn=$currentMeasObjLdn]/h:measResults" >
            <xsl:value-of select="concat(.,'---')"/> <!-- is an optional separator. -->
        </xsl:for-each>
    </xsl:variable>
    
    <xsl:for-each select="str:tokenize($measObjLdns,'---')" ><!-- Since position() doesn't 
    
    work as expected(returning node position of current node list), 
    I got round it by a string variable and tokenizing it in which
    absolute position is equal to relative(context) position. -->
    
        <xsl:value-of select="."></xsl:value-of>
        <xsl:if test="position() != last()">
            <xsl:text>,</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:if test="position() != last()">
        <xsl:text>,</xsl:text>
    </xsl:if>
    
        5
  •  1
  •   Martin Peck    17 年前

        6
  •  -4
  •   Matt    17 年前

    <xsl:if test="Locality != ''">
        <xsl:value-of select="Locality"/>
        <xsl:if test="CollectorAndNumber != '' or Institution != '' or Distribution != '' or Note != ''">
            <xsl:value-of select="','"/>
        </xsl:if>
    </xsl:if>
    <xsl:if test="CollectorAndNumber != ''">
        <xsl:value-of select="CollectorAndNumber"/>
        <xsl:if test="Institution != '' or Distribution != '' or Note != ''">
            <xsl:value-of select="','"/>
        </xsl:if>
    </xsl:if>
    <xsl:if test="Institution != ''">
        <xsl:value-of select="Institution"/>
        <xsl:if test="Distribution != '' or Note != ''">
            <xsl:value-of select="','"/>
        </xsl:if>
    </xsl:if>
    <xsl:if test="Distribution != ''">
        <xsl:value-of select="Distribution"/>
        <xsl:if test="Note != ''">
            <xsl:value-of select="','"/>
        </xsl:if>
    </xsl:if>
    <xsl:if test="Note != ''">
        <xsl:value-of select="Note"/>
    </xsl:if>