使用XSL重构XML

时间:2010-11-04 12:09:57

标签: xml xslt

我需要移动相应<sectionid/>内的<sponsor/><amendment/>元素。

以下是一个例子:

来自:

<root>
      <sectionid>A</sectionid>
      <sponsor>john</sponsor>
      <sponsor>paul</sponsor>
      <amendment>
            <id>1</id>
            <text>some text</text>
      </amendment>
      <sectionid>B</sectionid>
      <sponsor>peter</sponsor>
      <amendment>
            <id>5</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <id>4</id>
            <text>some text</text>
      </amendment>
      <sponsor>max</sponsor>
      <amendment>
            <id>6</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <id>7</id>
            <text>some text</text>
      </amendment>

</root>

为:

<root>
      <amendment>
            <sectionid>A</sectionid>
            <sponsor>john</sponsor>
            <sponsor>paul</paul>
            <id>1</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <sectionid>B</sectionid>
            <sponsor>peter</sponsor>
            <id>5</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <sectionid>B</sectionid>
            <sponsor>peter</sponsor>
            <id>4</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <sectionid>B</sectionid>
            <sponsor>max</sponsor>
            <id>6</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <sectionid>B</sectionid>
            <sponsor>max</sponsor>
            <id>7</id>
            <text>some text</text>
      </amendment>

</root>

注1:<section/>元素适用于下一个<amendments/>之前的所有<sectionid/>

注意2:<sponsor/>元素适用于下一个<amendments/>列表之前的所有<sponsor/>

注3://amendment/id的值不是连续的。

如何使用XSLT 1.0完成此转换。

2 个答案:

答案 0 :(得分:1)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:param name="pSectionId"/>
        <xsl:param name="pSponsors"/>
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pSectionId" select="$pSectionId"/>
            <xsl:with-param name="pSponsors" select="$pSponsors"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="sectionid">
        <xsl:param name="pSectionId"/>
        <xsl:param name="pSponsors"/>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pSectionId" select="."/>
            <xsl:with-param name="pSponsors" select="$pSponsors"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="sponsor">
        <xsl:param name="pSectionId"/>
        <xsl:param name="pSponsors"/>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pSectionId" select="$pSectionId"/>
            <xsl:with-param name="pSponsors" select="."/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="sponsor[preceding-sibling::node()[1]/self::sponsor]">
        <xsl:param name="pSectionId"/>
        <xsl:param name="pSponsors"/>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pSectionId" select="$pSectionId"/>
            <xsl:with-param name="pSponsors" select="$pSponsors|."/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="amendment">
        <xsl:param name="pSectionId"/>
        <xsl:param name="pSponsors"/>
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:copy-of select="$pSectionId|$pSponsors"/>
            <xsl:apply-templates select="node()[1]"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pSectionId" select="$pSectionId"/>
            <xsl:with-param name="pSponsors" select="$pSponsors"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

输出:

<root>
    <amendment>
        <sectionid>A</sectionid>
        <sponsor>john</sponsor>
        <sponsor>paul</sponsor>
        <id>1</id>
        <text>some text</text>
    </amendment>
    <amendment>
        <sectionid>B</sectionid>
        <sponsor>peter</sponsor>
        <id>5</id>
        <text>some text</text>
    </amendment>
    <amendment>
        <sectionid>B</sectionid>
        <sponsor>peter</sponsor>
        <id>4</id>
        <text>some text</text>
    </amendment>
    <amendment>
        <sectionid>B</sectionid>
        <sponsor>max</sponsor>
        <id>6</id>
        <text>some text</text>
    </amendment>
    <amendment>
        <sectionid>B</sectionid>
        <sponsor>max</sponsor>
        <id>7</id>
        <text>some text</text>
    </amendment>
</root>

注意:细粒度遍历。线性复杂性。

修改:新输入样本。

答案 1 :(得分: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:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="amendment">
  <xsl:copy>
     <xsl:apply-templates select="@*"/>

     <xsl:variable name="vSectionId" 
          select="preceding-sibling::sectionid[1]"/>
     <xsl:variable name="vprevAmendment" 
          select="preceding-sibling::amendment[1]"/>

     <xsl:apply-templates select="$vSectionId" mode="copy"/>

     <xsl:variable name="vsectSponsors"
      select="preceding-sibling::sponsor
               [generate-id(preceding-sibling::sectionid[1])
               =
                generate-id($vSectionId)
               ]"/>

     <xsl:variable name="vamdSponsors"
      select="preceding-sibling::sponsor
               [generate-id(preceding-sibling::amendment[1])
               =
                generate-id($vprevAmendment)
               ]"/>


     <xsl:apply-templates mode="copy"
          select="$vamdSponsors|$vsectSponsors[not($vamdSponsors)]"/>
    <xsl:apply-templates select="node()|@*"/>
   </xsl:copy>
 </xsl:template>

 <xsl:template match="*" mode="copy">
  <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match="sectionid|sponsor"/>
</xsl:stylesheet>

应用于提供的XML文档

<root>
      <sectionid>A</sectionid>
      <sponsor>john</sponsor>
      <sponsor>paul</sponsor>
      <amendment>
            <id>1</id>
            <text>some text</text>
      </amendment>
      <sectionid>B</sectionid>
      <sponsor>peter</sponsor>
      <amendment>
            <id>5</id>
            <text>some text</text>
      </amendment>
      <amendment>
            <id>4</id>
            <text>some text</text>
      </amendment>
      <sponsor>max</sponsor>
      <amendment>
            <id>6</id>
            <text>some text</text>
      </amendment>
</root>

生成想要的正确结果

<root>
   <amendment>
      <sectionid>A</sectionid>
      <sponsor>john</sponsor>
      <sponsor>paul</sponsor>
      <id>1</id>
      <text>some text</text>
   </amendment>
   <amendment>
      <sectionid>B</sectionid>
      <sponsor>peter</sponsor>
      <id>5</id>
      <text>some text</text>
   </amendment>
   <amendment>
      <sectionid>B</sectionid>
      <sponsor>peter</sponsor>
      <id>4</id>
      <text>some text</text>
   </amendment>
   <amendment>
      <sectionid>B</sectionid>
      <sponsor>max</sponsor>
      <id>6</id>
      <text>some text</text>
   </amendment>
</root>