2013-06-14 3 views
1

Так что у меня этот XML:Устройте узлы под закрытым элементом - XSLT

<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 s и Block s, расположенных в первом 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> 

Тогда элементы под Position 5 в Type B будут перемещены оттуда под Position 5 в TypeA. И я не хочу этого. Я хочу, чтобы Дома и Блоки были организованы, но оставались в их собственных типах и областях.

Может ли кто-нибудь предоставить мне решение о том, как мне изменить XSLT, чтобы исправить это?

P.S. имена XML-тегов были изменены для упрощения. И я не могу использовать xslt-2.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> 

Единственное, что следует отметить, что «труба» символ в конкатенации может быть любой символ, который вы хотите, только до тех пор, как это не происходит ни в одном из Тип и Позиция элементов, чтобы обеспечить две разные комбинации таких элементов не приводят к одному и тому же ключу.

Смежные вопросы