使用XSLT检索XML中的属性值

时间:2015-01-24 19:27:01

标签: xml xslt

要扩展提供的解决方案here,目的是检索属性的值以及它们的名称。

对于本文档,

<a>
    <apple color="red"/>
    <apple color="green"/>
    <banana color="yellow"/>
    <sugar taste="sweet"/>
    <cat size="small"/>
</a>

上面的帖子中的代码提供了这样的结果:

For tags: apple 2, banana 1, sugar 1, cat 1 
For attributes: color 3, taste 1, size 1 

现在,期望的结果是:

For tags: apple 2, banana 1, sugar 1, cat 1 
For attributes: color(red) 1, color(green) 1, color(yellow) 1, taste(sweet) 1, size (small) 1

非常感谢。

1 个答案:

答案 0 :(得分:2)

要扩展Rudramuni TP提供的solution for your previous question,您可以添加其他密钥以获取唯一属性值:

<xsl:key name="kAttribValue" match="@*" use="."/>

和另一个变量:

<xsl:variable name="var2">
  <xsl:for-each select="/a/*/@*[generate-id() = generate-id(key('kAttribValue', .))]">
     <xsl:value-of select="concat(name(.), '(', .,')', ' ', count(key('kAttribValue', .)))"/>
       <xsl:if test="not(position()=last())">
         <xsl:text>, </xsl:text>
       </xsl:if>
  </xsl:for-each>
</xsl:variable>

对Rudramuni TPs代码的这些调整:

<?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" omit-xml-declaration="yes"/>
  <xsl:key name="kEleName" match="*" use="local-name()"/>
  <xsl:key name="kAttribName" match="@*" use="local-name()"/>
  <xsl:key name="kAttribValue" match="@*" use="."/>

  <xsl:variable name="var1">
    <xsl:for-each select="/a/*/@*[generate-id() = generate-id(key('kAttribName', name()))]">
      <xsl:value-of select="concat(name(.), ' ', count(key('kAttribName', name(.))))"/>
      <xsl:if test="not(position()=last())">
        <xsl:text>, </xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>
  <xsl:variable name="var2">
    <xsl:for-each select="/a/*/@*[generate-id() = generate-id(key('kAttribValue', .))]">
      <xsl:value-of select="concat(name(.), '(', .,')', ' ', count(key('kAttribValue', .)))"/>
      <xsl:if test="not(position()=last())">
        <xsl:text>, </xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:template match="/*">
    <xsl:apply-templates select="*[generate-id() = generate-id(key('kEleName', name()))]"/>
  </xsl:template>
  <xsl:template match="*">
    <xsl:if test="position()=1"><xsl:text>For tags: </xsl:text></xsl:if>
        <xsl:value-of select="concat(name(.), ' ', count(key('kEleName', name(.))))"/>
        <xsl:if test="following-sibling::*">
          <xsl:text>, </xsl:text>
        </xsl:if>
        <xsl:if test="position()=last()">
          <xsl:text>&#10;For attributes: </xsl:text>
        <xsl:value-of select="$var2"/>
     </xsl:if>
  </xsl:template>
</xsl:stylesheet>

应用于输入XML

<a>
  <apple color="red"/>
  <apple color="green"/>
  <banana color="yellow"/>
  <sugar taste="sweet"/>
  <cat size="small"/>
</a>

生成扩展结果:

For tags: apple 2, banana 1, sugar 1, cat 1
For attributes: color(red) 1, color(green) 1, color(yellow) 1, taste(sweet) 1, size(small) 1

更新:正如评论中所述,上述调整(以及上一个问题的答案)仅适用于问题中提供的输入。给定输入XML,例如

<root>
  <a>
    <apple color="red"/>
    <apple color="green"/>
    <banana color="yellow"/>
    <sugar taste="sweet"/>
    <cat size="small"/>
  </a>
  <a>
    <apple color="red"/>
    <apple color="green"/>
    <banana color="yellow"/>
    <sugar taste="sweet"/>
    <dog size="big"/>
  </a>
</root> 

模板可以按如下方式进行调整:

<?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" omit-xml-declaration="yes"/>
  <xsl:key name="kEleName" match="*" use="local-name()"/>
  <xsl:key name="kAttribName" match="@*" use="local-name()"/>
  <xsl:key name="kAttribValue" match="@*" use="."/>

  <xsl:variable name="var1">
    <xsl:for-each select="//a/*/@*[generate-id() = generate-id(key('kAttribValue', .))]">
      <xsl:value-of select="concat(name(.), ' (', .,')', ' ', count(key('kAttribValue', .)))"/>
      <xsl:if test="not(position()=last())">
        <xsl:text>, </xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:template match="/*">
    <xsl:apply-templates select="a/*[generate-id() = generate-id(key('kEleName', name()))]"/>
  </xsl:template>
  <xsl:template match="*">
    <xsl:if test="position()=1"><xsl:text>For tags: </xsl:text></xsl:if>
      <xsl:value-of select="concat(name(.), ' ', count(key('kEleName', name(.))))"/>
      <xsl:if test="following::*">
        <xsl:text>, </xsl:text>
      </xsl:if>
      <xsl:if test="position()=last()">
        <xsl:text>&#10;For attributes: </xsl:text>
        <xsl:value-of select="$var1"/>
      </xsl:if>
  </xsl:template>
</xsl:stylesheet>

当这应用于调整后的示例输入XML时,会生成输出:

For tags: apple 4, banana 2, sugar 2, cat 1, dog 1
For attributes: color (red) 2, color (green) 2, color (yellow) 2, taste (sweet) 2, size (small) 1, size (big) 1

调整如下:

<xsl:for-each select="/a/*/@*[generate-id() = generate-id(key('kAttribValue', .))]">

必须调整为

<xsl:for-each select="//a/*/@*[generate-id() = generate-id(key('kAttribValue', .))]">

否则仅匹配第一个a节点的子节点的属性。

<xsl:apply-templates select="*[generate-id() = generate-id(key('kEleName', name()))]"/>

必须调整为

<xsl:apply-templates select="a/*[generate-id() = generate-id(key('kEleName', name()))]"/>

否则将选择a标签(这将产生输出     For tags: a 2,)。

这个

<xsl:if test="following-sibling::*">
  <xsl:text>, </xsl:text>
</xsl:if>

必须调整为

<xsl:if test="following::*">
  <xsl:text>, </xsl:text>
</xsl:if>

因为第二个dog节点中添加的a不是跟随兄弟,但仍然是跟随元素。

很明显,如果未知的要求允许具有不同的命名父节点,则此调整将不会工作 - 作为简化示例,它将不适用于像

这样的输入
<a>
  <apple color="red"/>
  <apple color="green"/>
</a>
<b>
  <banana color="yellow"/>
</b>

如果不同的父节点或嵌套结构,例如

<a>
  <apple color="red"/>
  <apple color="green"/>
  <b>
    <banana color="yellow"/>
  </b>
</a>

也应该处理,我建议为此提出一个新问题,因为这与问题中提供的示例输入XML有很大不同。