необходимо объединить узлы XML на основе значения атрибута - PullRequest
1 голос
/ 30 июля 2010

Мне нужно объединить определенные узлы xml на основе значения атрибута, изменить значение этого атрибута на объединенном узле и суммировать другой атрибут.

Я могу изменить значение атрибутов, но я не смог 't выяснить, как суммировать (@count) и присвоить его @count в полученном xml

Source 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 ]

1 голос
/ 30 июля 2010

Это преобразование :

<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>
0 голосов
/ 30 июля 2010

Другая таблица стилей без ключа:

<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?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...