1

所以我有这个 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那么我会将所有Houses 和Blocks 安排在Type我有重复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>

然后 in 下的元素Position 5将从Type B那里移动到Position 5in下TypeA。我不希望那样。我希望安排房屋和街区,但要保留在自己的类型和区域中。

谁能为我提供如何更改我的 XSLT 才能解决此问题的解决方案?

PS 为简化起见,更改了 XML 标记的名称。而且我不能使用 xslt-2.0,因为我的编辑器不支持它。

4

1 回答 1

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>

唯一需要注意的是,连接中的“管道”字符可以是您喜欢的任何字符,只要它不在TypePosition元素中出现,以确保不会导致此类元素的两种不同组合在同一个键。

于 2013-06-14T13:49:20.100 回答