使用递归嵌套多个XSLT模板

时间:2016-04-19 22:42:30

标签: xml xslt

我的XML非常扁平,这是一个例子:

<?xml version="1.0" encoding="UTF-8"?>
<Elements>
  <Header>
     <Divison>A</Divison>
     <ParentNumber>2016041330</ParentNumber>
  </Header>
  <Header>
     <Divison>C</Divison>
     <ParentNumber>2016041323</ParentNumber>
  </Header>
  <Element>
     <Number>2016041312</Number>
     <ParentNumber>2016041330</ParentNumber>
     <Risk>8</Risk>
  </Element>
  <Element>
     <Number>2016041342</Number>
     <ParentNumber>2016041323</ParentNumber>
     <Risk>2</Risk>
  </Element>
  <Element>
     <Number>2016041318</Number>
     <ParentNumber>2016041330</ParentNumber>
     <Risk>0</Risk>
  </Element>
  <Element>
     <Number>2016041330</Number>
     <ParentNumber>2016041323</ParentNumber>
     <Risk>7</Risk>
  </Element>
</Elements>

它们需要以这样的方式嵌套:

<?xml version="1.0" encoding="UTF-8"?>
<Elements>
  <Header>
    <Divison>C</Divison>
    <ParentNumber>2016041323</ParentNumber>
    <Element>
       <Number>2016041342</Number>
       <ParentNumber>2016041323</ParentNumber>
       <Risk>2</Risk>
    </Element>
    <Header>
       <Divison>A</Divison>
       <ParentNumber>2016041330</ParentNumber>
       <Risk>7</Risk>
       <Element>
          <Number>2016041312</Number>
          <ParentNumber>2016041330</ParentNumber>
          <Risk>8</Risk>
       </Element>
       <Element>
          <Number>2016041318</Number>
          <ParentNumber>2016041330</ParentNumber>
          <Risk>0</Risk>
       </Element>
    </Header>
  </Header>
</Elements>

我尝试了以下转换:

  

(特别感谢michael.hor257k)

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

<xsl:key name="child-by-parent" match="Header | Element" use="ParentNumber" />
<xsl:key name="parent" match="Header | Element" use="Number" />

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

<xsl:template match="Elements">
    <xsl:copy>
        <xsl:apply-templates select="*[not(key('parent', ParentNumber))]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Header | Element">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:apply-templates select="key('child-by-parent', Number)"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

具有以下结果:

<?xml version="1.0" encoding="UTF-8"?>
<Elements>
   <Header>
      <Divison>C</Divison>
      <ParentNumber>2016041323</ParentNumber>
   </Header>
   <Element>
      <Number>2016041342</Number>
      <ParentNumber>2016041323</ParentNumber>
      <Risk>2</Risk>
   </Element>
   <Element>
      <Number>2016041330</Number>
      <ParentNumber>2016041323</ParentNumber>
      <Risk>7</Risk>
      <Header>
         <Divison>A</Divison>
         <ParentNumber>2016041330</ParentNumber>
      </Header>
      <Element>
         <Number>2016041312</Number>
         <ParentNumber>2016041330</ParentNumber>
         <Risk>8</Risk>
      </Element>
      <Element>
         <Number>2016041318</Number>
         <ParentNumber>2016041330</ParentNumber>
         <Risk>0</Risk>
      </Element>
   </Element>
</Elements>

[element]标签包含两种信息:number和parentnumber。数字是[元素]的不同数字。 parentnumber引用另一个[element]。数字和父数字都对应于[标题],然后[元素]用作链接并且可以解散。但是,如果只有父编号与[header]相对应,则将[element]标记分配给[header]标记。

1 个答案:

答案 0 :(得分:1)

我不明白你获得结果的逻辑。 AFAICS,您有三个没有父节点的元素:

<Header>
  <Divison>C</Divison>
  <ParentNumber>2016041323</ParentNumber>
</Header>
<Element>
  <Number>2016041342</Number>
  <ParentNumber>2016041323</ParentNumber>
</Element>
<Element>
  <Number>2016041330</Number>
  <ParentNumber>2016041323</ParentNumber>
</Element>

所以我希望这些是兄弟姐妹在层次结构的顶层。然后你会让这三个分支中的每一个递归地嵌套它们的后代 - 获得:

<Elements>
   <Header>
      <Divison>C</Divison>
      <ParentNumber>2016041323</ParentNumber>
   </Header>
   <Element>
      <Number>2016041342</Number>
      <ParentNumber>2016041323</ParentNumber>
   </Element>
   <Element>
      <Number>2016041330</Number>
      <ParentNumber>2016041323</ParentNumber>
      <Header>
         <Divison>A</Divison>
         <ParentNumber>2016041330</ParentNumber>
      </Header>
      <Element>
         <Number>2016041312</Number>
         <ParentNumber>2016041330</ParentNumber>
      </Element>
      <Element>
         <Number>2016041318</Number>
         <ParentNumber>2016041330</ParentNumber>
      </Element>
   </Element>
</Elements>

这可以通过以下方式实现:

XSLT 1.0

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

<xsl:key name="child-by-parent" match="Header | Element" use="ParentNumber" />
<xsl:key name="parent" match="Header | Element" use="Number" />

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

<xsl:template match="Elements">
    <xsl:copy>
        <xsl:apply-templates select="*[not(key('parent', ParentNumber))]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Header | Element">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
        <xsl:apply-templates select="key('child-by-parent', Number)"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>