在一个封闭的元素下安排节点 - XSLT

时间:2013-06-14 13:36:15

标签: xml xslt xslt-1.0 xslt-grouping muenchian-grouping

所以我有这个XML:

<Main>
 <TB>
    --> some elements - not relevant
   <Area>
     <Type>A</Type>
     <Street>
       <Position>5</Position>
       <House>

       --> some elements

       </House>
     </Street>
     <Street>
       <Position>5</Position>
       <Block>

       --> some elements

       </Block>
     </Street>
     <Street>
       <Position>6</Position>
       <House>

       --> some elements

       </House>
     </Street>
     <Street>
       <Position>6</Position>
       <Block>

       --> some elements

       </Block>
     </Street>
   </Area>
   <Area>
    <Type>B</Type>
   --> same structure but with several repetitions of Position 7 and 8.

   </Area>
 </TB>
</Main>

我想这样订购:

<Area>
   <Type>A</Type>
     <Street>
       <Position>5</Position>
       <House>

       --> some elements

       </House>
       <Block>

       --> some elements

       </Block>
     </Street>
     <Street>
       <Position>6</Position>
       <House>

       --> some elements

       </House>
       <Block>

       --> some elements

       </Block>
     </Street>
   </Area>
   <Area>
     <Type>B</Type>
   --> same structure for Position 7 and 8.

   </Area>

我正在使用此XSLT对其进行转换:

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

  <xsl:key name="streetByPosition" match="Street" use="Position" />

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

  <!-- for the first Street in each Position -->
  <xsl:template match="Street[generate-id() =
                            generate-id(key('streetByPosition', Position)[1])]">
    <Street>
      <!-- copy in the Position element once only -->
      <xsl:apply-templates select="Position" />
      <!-- copy in all sub-elements except Position from all matching Streets-->
      <xsl:apply-templates select="
            key('streetByPosition', Position)/*[not(self::Position)]" />
    </Street>
  </xsl:template>

  <!-- ignore all other Street elements -->
  <xsl:template match="Street" />
</xsl:stylesheet>

订购完全正常。 但是,如果我在不同的Position中有重复的Type个数字,那么我会在第一个House中排列所有BlockType Position号码。 例如:

<Area>
         <Type>A</Type>
         <Street>
           <Position>5</Position>
           <House>

           --> some elements

           </House>
         </Street>
         <Street>
           <Position>5</Position>
           <Block>

           --> some elements

           </Block>
         </Street>
....
<Area>
     <Type>B</Type>
     <Street>
       <Position>5</Position>
       <House>

       --> some elements

       </House>
     </Street>

然后Position 5Type B下的元素将从Position 5移到TypeA下的{{1}}下。我不希望这样。我想要安排房屋和街区,但要留在他们自己的类型和区域。

任何人都可以向我提供解决方案,我该如何更改我的XSLT以解决此问题?

P.S。出于简化原因,更改了XML标记的名称。我不能使用xslt-2.0,因为我的编辑器不支持它。

1 个答案:

答案 0 :(得分:2)

要执行此操作,您需要一个复合键,它将是标识您的组的所有值的串联,在您的情况下是类型(父元素的),以及的位置

<xsl:key name="streetByPosition" match="Street" use="concat(../Type, '|', Position)" />

然后您可以按正常方式使用密钥

key('streetByPosition', concat(../Type, '|', Position))

尝试以下XSLT:

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

  <xsl:key name="streetByPosition" match="Street" use="concat(../Type, '|', Position)" />

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

  <!-- for the first Street in each Position -->
  <xsl:template match="Street[generate-id() =
                            generate-id(key('streetByPosition', concat(../Type, '|', Position))[1])]">
    <Street>
      <!-- copy in the Position element once only -->
      <xsl:apply-templates select="Position" />
      <!-- copy in all sub-elements except Position from all matching Streets-->
      <xsl:apply-templates select="
            key('streetByPosition', concat(../Type, '|', Position))/*[not(self::Position)]" />
    </Street>
  </xsl:template>

  <!-- ignore all other Street elements -->
  <xsl:template match="Street" />
</xsl:stylesheet>

唯一要注意的是,连接中的“管道”字符可以是您喜欢的任何字符,只要它不会出现在类型位置中的任何一个元素,确保这些元素的两种不同组合不会产生相同的键。