使用XSLT计算xml标记值,而不考虑标记名称

时间:2017-11-28 21:40:05

标签: xml xslt xpath

我有一个场景,我需要计算xml标记值,而不管它的标记名称。下面是我的xml,

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <result>
      <value>
         <color1>G</color1>
         <color2>Y</color2>
      </value>
      <value>
         <color1>Y</color1>
         <color2>R</color2>
      </value>
   </result>
   <result>
      <value>
         <color1>G</color1>
         <color2>R</color2>
      </value>
      <value>
         <color1>Y</color1>
         <color2>R</color2>
      </value>
   </result>
</output>
  1. 这里我需要从xpath // output / result
  2. 计算G,Y,R的出现次数
  3. // output / result里面的值应该保留,并且能够在输出中添加它。下面是我使用的xslt,但它总是将count计为0。

     <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"     
          xmlns:xs="http://www.w3.org/2001/XMLSchema" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
    
        <xsl:template match="/">
           <output>
              <xsl:for-each select="//output/result">
                 <result>
        <green><xsl:value-of select="count(/value[./color[*]='G'])" /></green>
         <red><xsl:value-of select="count(/value[./color[*]='R'])" /></red>
         <yellow><xsl:value-of select="count(/value[./color[*]='Y'])" /</yellow>
                   <xsl:value-of select="." />
                </result>
             </xsl:for-each>
          </output>
       </xsl:template>
    </xsl:stylesheet>
    
  4. 所需的输出如下。

    <?xml version="1.0" encoding="UTF-8"?>
    <output>
       <result>
         <GreenCount>1</GreenCount>
    <RedCount>1</RedCount>
    <YellowCount>2</YellowCount>
          <value>
             <color1>G</color1>
             <color2>Y</color2>
          </value>
          <value>
             <color1>Y</color1>
             <color2>R</color2>
          </value>
    
       </result>
       <result>
         <GreenCount>1</GreenCount>
    <RedCount>2</RedCount>
    <YellowCount>1</YellowCount>
    
          <value>
             <color1>G</color1>
             <color2>R</color2>
          </value>
          <value>
             <color1>Y</color1>
             <color2>R</color2>
          </value>
       </result>
    </output>
    

1 个答案:

答案 0 :(得分:1)

您正在尝试将XSL编程为一种命令式语言。事实并非如此,输入XML正在推动流程,而XSL会在输入标签与模板匹配时“作出反应”。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="result">
        <xsl:copy>
            <GreenCount><xsl:value-of select="count(value/*[text() = 'G'])"/> </GreenCount>
            <RedCount><xsl:value-of select="count(value/*[text() = 'R'])"/></RedCount>
            <YellowCount><xsl:value-of select="count(value/*[text() = 'Y'])"/></YellowCount>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

第一个模板是一个“标识转换”,它将输入复制到输出,因为您只是在输入中添加标签。

然后,对于每个result(不是XSL for-each,只需让处理的自然顺序为result元素提供):

  1. 复制result代码
  2. 通过计算具有所需文本的value标记的子项
  3. 来生成三个摘要标记
  4. 对于result标记的其余内容,使用标识转换递归重新调用该过程以将它们复制到输出。
  5. 这会产生以下输出:

    <?xml version="1.0" encoding="UTF-8"?>
    <output>
        <result>
          <GreenCount>1</GreenCount>
          <RedCount>1</RedCount>
          <YellowCount>2</YellowCount>
            <value>
                <color1>G</color1>
                <color2>Y</color2>
            </value>
            <value>
                <color1>Y</color1>
                <color2>R</color2>
            </value>
        </result>
        <result>
          <GreenCount>1</GreenCount>
          <RedCount>2</RedCount>
          <YellowCount>1</YellowCount>
            <value>
                <color1>G</color1>
                <color2>R</color2>
            </value>
            <value>
                <color1>Y</color1>
                <color2>R</color2>
            </value>
        </result>
    </output>
    
相关问题