Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用XSLT计算不同的项并解析逗号分隔的值_Xslt_Parsing - Fatal编程技术网

使用XSLT计算不同的项并解析逗号分隔的值

使用XSLT计算不同的项并解析逗号分隔的值,xslt,parsing,Xslt,Parsing,假设我有如下XML: <child_metadata> <metadata> <attributes> <metadata_valuelist value="[SampleItem3]"/> </attributes> </metadata> <metadata> <attributes>

假设我有如下XML:

<child_metadata>
    <metadata>
        <attributes>
            <metadata_valuelist value="[SampleItem3]"/>
        </attributes>
    </metadata>
    <metadata>
        <attributes>
            <metadata_valuelist value="[SampleItem1]"/>
        </attributes>
    </metadata>
    <metadata>
        <attributes>
            <metadata_valuelist value="[SampleItem1, SampleItem2]"/>
        </attributes>
    </metadata>
</child_metadata>
...
<metadata_valuelist>
  <value>SampleItem1</value>
  <value>SampleItem2</value>
</metadata_valuelist>
...

我要做的是计算元数据值列表中不同值的数量。有以下不同的值:SampleItem1、SampleItem2和SampleItem3。所以,我想得到一个值3。(虽然SampleItem1出现了两次,但我只计算了一次。)

如何在XSLT中实现这一点


我意识到这里有两个问题:第一,在列表中分隔逗号分隔的值,第二,计算唯一值的数量。然而,我不确定我是否能将这两个问题的解决方案结合起来,这就是为什么我要把它作为一个问题来问。

你可能想分两个阶段来考虑;首先,进行分解这些值属性的转换,然后对它们进行计数就相当简单了

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="@value">
    <xsl:call-template name="breakdown">
      <xsl:with-param name="itemlist" select="substring-before(substring-after(.,'['),']')" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="breakdown">
    <xsl:param name="itemlist" />
    <xsl:choose>
      <xsl:when test="contains($itemlist,',')">
        <xsl:element name="value">
          <xsl:value-of select="normalize-space(substring-before($itemlist,','))" />
        </xsl:element>
        <xsl:call-template name="breakdown">
          <xsl:with-param name="itemlist" select="substring-after($itemlist,',')" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="value">
          <xsl:value-of select="normalize-space($itemlist)" />
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

除了底部的“一网打尽”模板外,它还会以您提供的格式提取任何值属性,并将它们分解为单独的元素(作为“元数据\ U valuelist”元素的子元素),如下所示:

<child_metadata>
    <metadata>
        <attributes>
            <metadata_valuelist value="[SampleItem3]"/>
        </attributes>
    </metadata>
    <metadata>
        <attributes>
            <metadata_valuelist value="[SampleItem1]"/>
        </attributes>
    </metadata>
    <metadata>
        <attributes>
            <metadata_valuelist value="[SampleItem1, SampleItem2]"/>
        </attributes>
    </metadata>
</child_metadata>
...
<metadata_valuelist>
  <value>SampleItem1</value>
  <value>SampleItem2</value>
</metadata_valuelist>
...
。。。
样本项目1
样本项目2
...
在将“[”和“]”传递到“细分”模板之前,顶部附近的“选择前的子字符串/选择后的子字符串”会将“[”和“]”去掉。此模板将检查它的“itemlist”参数中是否有逗号,如果有,它会将前面的文本作为“value”元素的内容吐出,然后使用列表的其余部分递归调用自己。如果参数中没有逗号,它只将参数的整个内容作为“value”元素输出

然后运行以下命令:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" />

  <xsl:key name="itemvalue" match="value" use="text()" />

  <xsl:template match="/">
    <xsl:value-of select="count(//value[generate-id(.) = generate-id(key('itemvalue',.)[1])])" />
  </xsl:template>
</xsl:stylesheet>

在第一次转换得到的XML上,它只会输出一个值作为文本输出,告诉您有多少不同的值

编辑:我可能应该指出,这个解决方案对您的输入做出了一些假设:

  • 文档中其他任何位置都没有名为“value”的属性;如果有,您可以修改@value匹配来特别挑选这些
  • 文档中其他任何位置都没有名为“value”的元素;当第一个变换创建它们时,第二个变换将无法区分两者。如果有,您可以用尚未使用的元素名称替换这两行
  • @value属性的内容始终以“[”开头,以“]”结尾,列表中没有“]”字符;如果存在,则“substring before”函数将删除第一个']'之后的所有内容,而不仅仅是结尾的']'
  • 要计数的项目名称中没有逗号,例如[SampleItem1,“Sample2,3”]。如果有,“‘样本2’和‘样本3’”将被视为单独的项目

    • 另一种没有扩展的方式:

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
      
          <xsl:variable name="all-value" select="/*/*/*/*/@value"/> 
      
          <xsl:template match="/"> 
              <xsl:variable name="count"> 
                  <xsl:apply-templates select="$all-value"/> 
              </xsl:variable> 
              <xsl:value-of select="string-length($count)"/> 
          </xsl:template>  
      
          <xsl:template match="@value" name="value">
              <xsl:param name="meta" select="translate(.,'[] ','')"/>
              <xsl:choose>
                  <xsl:when test="contains($meta,',')">
                      <xsl:call-template name="value">
                          <xsl:with-param name="meta" select="substring-before($meta,',')"/>
                      </xsl:call-template>
                      <xsl:call-template name="value">
                          <xsl:with-param name="meta" select="substring-after($meta,',')"/>
                      </xsl:call-template>
                  </xsl:when>
                  <xsl:otherwise>
                      <xsl:if test="count(.|$all-value[contains(translate(.,'[] ','&#xA;&#xA;&#xA;'),
                                                                concat('&#xA;',$meta,'&#xA;'))][1])=1">
                          <xsl:value-of select="1"/> 
                      </xsl:if> 
                  </xsl:otherwise>
              </xsl:choose>
          </xsl:template> 
      
      </xsl:stylesheet> 
      
      
      
      注意:可能可以使用
      xsl:key
      而不是
      xsl:variable
      编辑:匹配棘手的元数据。

      此(注意:仅一个)转换

      <xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:msxsl="urn:schemas-microsoft-com:xslt"
       >
       <xsl:output method="text"/>
       <xsl:strip-space elements="*"/>
      
       <xsl:key name="kValue" match="value" use="."/>
      
       <xsl:template match="/">
         <xsl:variable name="vRTFPass1">
          <values>
           <xsl:apply-templates/>
          </values>
         </xsl:variable>
      
         <xsl:variable name="vPass1"
              select="msxsl:node-set($vRTFPass1)"/>
      
         <xsl:for-each select="$vPass1">
           <xsl:value-of select=
            "count(*/value[generate-id()
                          =
                           generate-id(key('kValue', .)[1])
                          ]
                   )
            "/>
         </xsl:for-each>
       </xsl:template>
      
       <xsl:template match="metadata_valuelist">
        <xsl:call-template name="tokenize">
          <xsl:with-param name="pText" select="translate(@value, '[],', '')"/>
        </xsl:call-template>
       </xsl:template>
      
       <xsl:template name="tokenize">
          <xsl:param name="pText" />
      
          <xsl:choose>
            <xsl:when test="not(contains($pText, ' '))">
              <value><xsl:value-of select="$pText"/></value>
            </xsl:when>
            <xsl:otherwise>
              <value>
               <xsl:value-of select="substring-before($pText, ' ')"/>
              </value>
              <xsl:call-template name="tokenize">
               <xsl:with-param name="pText" select=
                "substring-after($pText, ' ')"/>
              </xsl:call-template>
            </xsl:otherwise>
          </xsl:choose>
       </xsl:template>
      </xsl:stylesheet>
      
      <child_metadata>
          <metadata>
              <attributes>
                  <metadata_valuelist value="[SampleItem3]"/>
              </attributes>
          </metadata>
          <metadata>
              <attributes>
                  <metadata_valuelist value="[SampleItem1]"/>
              </attributes>
          </metadata>
          <metadata>
              <attributes>
                  <metadata_valuelist value="[SampleItem1, SampleItem2]"/>
              </attributes>
          </metadata>
      </child_metadata>
      
      3
      

      请注意:因为这是一个XSLT1.0解决方案,所以有必要将第一次传递的结果从臭名昭著的RTF类型转换为常规树。这是使用XSLT 1.0处理器的xxx:node-set()函数完成的——在我的例子中,我使用了msxsl:node-set()。

      此解决方案在这种特殊情况下会产生预期的结果。但是,如果给定以下值:
      [SampleItem3]
      [SampleItem1SampleItem2,SampleItem2]
      [SampleItem1,SampleItem1SampleItem2]
      ,则会生成错误答案:3。正确的答案是:4.这是一个很好的解决方案;次要的一点,但是你不需要顶部有一个
      元素吗?@Dimitre:你说得对!我编辑答案。另外,我正在寻找一种不必两次导航树的解决方案。@flyn1179:你说得对。为了生成完整的样式表,它需要
      xsl:output
      。但有时我们倾向于将这些转换视为最大样式表的一部分,甚至视为包含或导入。谢谢!请注意我的后续问题: