Используйте XSLT для перечисления узлов с одинаковым именем - PullRequest
2 голосов
/ 21 июня 2010

У меня много много XML-файлов, которые часто содержат узлы несколько раз (каждый раз с разными данными). Пример:

 <?xml version="1.0" encoding="UTF-8"?>  
    <SomeName>  
      <Node>
        DataA
     </Node>  
     <Node>
        DataB
     </Node>  
      <Node>
        DataC
     </Node>  
      <AnotherNode>
        DataD
     </AnotherNode>
      <AnotherNode>
        DataE
     </AnotherNode>
      <AnotherNode>
        DataF
     </AnotherNode>
     <SingleNode>
        DataG
     </SingleNode>
   </SomeName>  

Желаемый результат будет:

  <?xml version="1.0" encoding="UTF-8"?>  
    <SomeName>  
      <Node1>
        DataA
     </Node1>  
     <Node2>
        DataB
     </Node2>  
      <Node3>
        DataC
     </Node3>  
      <AnotherNode1>
        DataD
     </AnotherNode1>
      <AnotherNode2>
        DataE
     </AnotherNode2>
      <AnotherNode3>
        DataF
     </AnotherNode3>
     <SingleNode>
        DataG
     </SingleNode>
   </SomeName>  

Проблема в том, что у меня нет списка всех повторяющихся имен узлов, поэтому мне нужно, чтобы XSLT проходил через все узлы и исчислял только те, которые существуют несколько раз. Это возможно?

У кого-нибудь есть хорошая идея, как этого добиться?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 21 июня 2010

Вы можете использовать count(preceding-sibling::*[name(.) = name(current())]), чтобы получить количество предшествующих элементов-братьев и сестер с тем же именем, что и у элемента контекста, и <xsl:element name="concat(name(.),'n')" />, чтобы создать элемент с тем же именем, что и у элемента контекста, с добавлением буквы 'n'. к этому. Объединение этих фактов должно позволить вам достичь желаемого эффекта.

1 голос
/ 21 июня 2010

Вот полное решение . Рекомендуется использовать метод Мюнхена для группировки, а не группировки на основе count(preceding::*[someCondition]), что крайне неэффективно - O (N ^ 2).

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kElsByName"
  match="/*/*" use="name()"/>

 <xsl:template match="/*">
   <SomeName>
     <xsl:for-each select=
      "*[generate-id()
        =
         generate-id(key('kElsByName', name())[1])
        ]
      ">

        <xsl:variable name="vsameNamedNodes" select=
         "key('kElsByName', name())"/>

        <xsl:variable name="vNumSameNamedNodes" select=
         "count($vsameNamedNodes)"/>

        <xsl:for-each select="$vsameNamedNodes">

         <xsl:element name="{concat(name(),
                             substring(position(),
                                       1 div ($vNumSameNamedNodes > 1)
                                       )
                                    )
                             }">
           <xsl:copy-of select="node()"/>
         </xsl:element>
       </xsl:for-each>
     </xsl:for-each>
   </SomeName>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

    <SomeName>
      <Node>
        DataA
     </Node>
     <Node>
        DataB
     </Node>
      <Node>
        DataC
     </Node>
      <AnotherNode>
        DataD
     </AnotherNode>
      <AnotherNode>
        DataE
     </AnotherNode>
      <AnotherNode>
        DataF
     </AnotherNode>
     <SingleNode>
        DataG
     </SingleNode>
   </SomeName>

дает требуемый результат :

<SomeName>
    <Node1>
        DataA
    </Node1>
    <Node2>
        DataB
    </Node2>
    <Node3>
        DataC
    </Node3>
    <AnotherNode1>
        DataD
    </AnotherNode1>
    <AnotherNode2>
        DataE
    </AnotherNode2>
    <AnotherNode3>
        DataF
    </AnotherNode3>
    <SingleNode>
        DataG
    </SingleNode>
</SomeName>
...