需要根据属性值合并xml节点

时间:2010-07-30 00:15:51

标签: xslt

我需要根据属性值合并某些xml节点,在合并节点上更改该属性值并对另一个属性求和。

我可以更改属性的值,但我无法弄清楚如何求和(@count)并将其分配给生成的xml上的@count

来源xml

<xml>
 <books category="X" count="2">
  <book name="bookx1"/>
  <book name="bookx2"/>
 </books>
 <books category="Y" count="3">
  <book name="booky1"/>
  <book name="booky2"/>
  <book name="booky3"/>
 </books>
 <books category="Z" count="2">
  <book name="bookz1"/>
  <book name="bookz2"/>
 </books></xml>

xslt转换后,它需要像这样

<xml>
 <books category="A" count="5">
  <book name="bookx1"/>
  <book name="bookx2"/>
  <book name="booky1"/>
  <book name="booky2"/>
  <book name="booky3"/>
 </books>
 <books category="Z" count="2">
  <book name="bookz1"/>
  <book name="bookz2"/>
 </books></xml>

这是我的部分xslt

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml"/>
 <xsl:template match="*">
  <xsl:element name="{local-name()}">
   <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
 </xsl:template>
 <xsl:template match="@*">
  <xsl:copy-of select="."/>
 </xsl:template>

 <xsl:template match="@category">
  <xsl:attribute name="category">
   <xsl:choose>
    <xsl:when test=".='X'">
     <xsl:text>A</xsl:text>
    </xsl:when>
    <xsl:when test=".='Y'">
     <xsl:text>A</xsl:text>
    </xsl:when>
    <xsl:when test=".='Z'">
     <xsl:text>B</xsl:text>
    </xsl:when>
    <xsl:otherwise>
     <xsl:value-of select="."/>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:attribute>
 </xsl:template>

 <xsl:template match="books[@category='X']"/>
 <xsl:template match="books[@category='Y']"/></xsl:transform>

2 个答案:

答案 0 :(得分:1)

此转化

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="kBooksByCat" match="books"
    use="@category = 'Z'"/>

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

 <xsl:template match="/*">
  <xml>
    <xsl:variable name="vNonZ"
      select="key('kBooksByCat', 'false')"/>

    <xsl:variable name="vCatZ"
      select="key('kBooksByCat', 'true')"/>

    <xsl:if test="$vNonZ">
     <books category="A" count="{sum($vNonZ/@count)}">
       <xsl:apply-templates select="$vNonZ/node()"/>
     </books>
    </xsl:if>
    <xsl:if test="$vCatZ">
     <books category="B" count="{sum($vCatZ/@count)}">
       <xsl:apply-templates select="$vCatZ/node()"/>
     </books>
    </xsl:if>
  </xml>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<xml>
 <books category="X" count="2">
  <book name="bookx1"/>
  <book name="bookx2"/>
 </books>
 <books category="Y" count="3">
  <book name="booky1"/>
  <book name="booky2"/>
  <book name="booky3"/>
 </books>
 <books category="Z" count="2">
  <book name="bookz1"/>
  <book name="bookz2"/>
 </books>
 </xml>

生成想要的正确结果

<xml>
   <books category="A" count="5">
      <book name="bookx1"/>
      <book name="bookx2"/>
      <book name="booky1"/>
      <book name="booky2"/>
      <book name="booky3"/>
   </books>
   <books category="B" count="2">
      <book name="bookz1"/>
      <book name="bookz2"/>
   </books>
</xml>

答案 1 :(得分:0)

另一个没有键的样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="books[@category='Z'][1]">
        <xsl:variable name="us" select="../books[@category='Z']"/>
        <books category="B" count="{sum($us/@count)}">
            <xsl:apply-templates select="$us/node()"/>
        </books>
    </xsl:template>
    <xsl:template match="books[@category!='Z'][1]">
        <xsl:variable name="us" select="../books[@category!='Z']"/>
        <books category="A" count="{sum($us/@count)}">
            <xsl:apply-templates select="$us/node()"/>
        </books>
    </xsl:template>
    <xsl:template match="books"/>
</xsl:stylesheet>

输出:

<xml>
    <books category="A" count="5">
        <book name="bookx1"></book>
        <book name="bookx2"></book>
        <book name="booky1"></book>
        <book name="booky2"></book>
        <book name="booky3"></book>
    </books>
    <books category="B" count="2">
        <book name="bookz1"></book>
        <book name="bookz2"></book>
    </books>
</xml>

注意:只是为了好玩。这两本书的模板非常接近。也许有办法在一个模板中表达这些。一些复杂的translate