Как я могу преобразовать это с помощью ключей - PullRequest
1 голос
/ 26 ноября 2010

Я могу написать ужасно плохой xslt без использования ключей, но он довольно медленный и грязный. Кто-нибудь знает, как я мог бы преобразовать следующий файл XML в ожидаемый результат чисто? Спасибо!

ввод:

<testExecution>
    <test>
        <test.1/>
        <test.2/>
        <test.3/>
    </test>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <executor>
        <executor.1/>
        <executor.2/>
        <executor.3/>
    </executor>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <invoker>
        <invoker.1/>
        <invoker.2/>
        <invoker.3/>
    </invoker>
    <recipient>
        <recipient.1/>
        <recipient.2/>
        <recipient.3/>
    </recipient>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
</testExecution>

результат:

<testExecution>
    <test>
        <test.1/>
        <test.2/>
        <test.3/>
    </test>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <people>
        <importantPeople>
            <executor>
                <executor.1/>
                <executor.2/>
                <executor.3/>
            </executor>
            <comment>
                <comment.1/>
                <comment.2/>
                <comment.3/>
            </comment>
            <comment>
                <comment.1/>
                <comment.2/>
                <comment.3/>
            </comment>
        </importantPeople>
        <invoker>
            <invoker.1/>
            <invoker.2/>
            <invoker.3/>
        </invoker>
    </people>
    <recipient>
        <recipient.1/>
        <recipient.2/>
        <recipient.3/>
    </recipient>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
</testExecution>

Ответы [ 2 ]

4 голосов
/ 26 ноября 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kElementByTest" match="invoker|recipient"
             use="generate-id(preceding-sibling::test[1])"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="executor">
        <xsl:variable name="vFollowing"
                      select="key('kElementByTest',
                                  generate-id(preceding-sibling::test[1]))"/>
        <people>
            <importantPeople>
                <xsl:call-template name="identity"/>
            </importantPeople>
            <xsl:apply-templates select="$vFollowing/self::invoker"
                                     mode="copy"/>
        </people>
        <xsl:apply-templates select="$vFollowing/self::recipient"
                             mode="copy"/>
    </xsl:template>
    <xsl:template match="invoker"/>
    <xsl:template match="recipient"/>
    <xsl:template match="node()" mode="copy">
        <xsl:call-template name="identity"/>
    </xsl:template>
</xsl:stylesheet>

Выход:

<testExecution>
    <test>
        <test.1></test.1>
        <test.2></test.2>
        <test.3></test.3>
    </test>
    <comment>
        <comment.1></comment.1>
        <comment.2></comment.2>
        <comment.3></comment.3>
    </comment>
    <people>
        <importantPeople>
            <executor>
                <executor.1></executor.1>
                <executor.2></executor.2>
                <executor.3></executor.3>
            </executor>
            <comment>
                <comment.1></comment.1>
                <comment.2></comment.2>
                <comment.3></comment.3>
            </comment>
            <comment>
                <comment.1></comment.1>
                <comment.2></comment.2>
                <comment.3></comment.3>
            </comment>
        </importantPeople>
        <invoker>
            <invoker.1></invoker.1>
            <invoker.2></invoker.2>
            <invoker.3></invoker.3>
        </invoker>
    </people>
    <recipient>
        <recipient.1></recipient.1>
        <recipient.2></recipient.2>
        <recipient.3></recipient.3>
    </recipient>
    <comment>
        <comment.1></comment.1>
        <comment.2></comment.2>
        <comment.3></comment.3>
    </comment>
    <comment>
        <comment.1></comment.1>
        <comment.2></comment.2>
        <comment.3></comment.3>
    </comment>
</testExecution>

Примечание : Мелкозернистый обход. Ключи для «только для этого теста» следующие. Пустые шаблоны для «закрыть этот уровень». Режим для стиля push "keep processing". Это может быть полный «стиль вытягивания», соответствующий «предшествующему знаку перед знаком».

1 голос
/ 26 ноября 2010

Это преобразование использует и переопределяет правило идентификации. Комментарии, следующие сразу за executor, извлекаются с использованием функции key(). executor, invoker и comment, следующие сразу за executor, копируются в специальном режиме с именем people. В обычном анонимном режиме они сопоставляются с пустым шаблоном, чтобы избежать их повторного копирования:

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

 <xsl:key name="kExecComments" match=
  "comment
          [preceding-sibling::*
              [not(self::comment)][1]
                       [self::executor]
          ]"
  use="generate-id(preceding-sibling::executor[1])"/>

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

 <xsl:template match="executor">
  <people>
    <importantPeople>
      <xsl:apply-templates mode="people"
        select=".|key('kExecComments', generate-id())"/>
    </importantPeople>
    <xsl:apply-templates mode="people" select=
    "following-sibling::invoker"/>
  </people>
 </xsl:template>

 <xsl:template match="executor|comment|invoker"
      mode="people">
    <xsl:call-template name="identity"/>
 </xsl:template>

 <xsl:template match=
  "invoker |
   comment
          [preceding-sibling::*
              [not(self::comment)][1]
                       [self::executor]
          ]"/>

</xsl:stylesheet>

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

<testExecution>
    <test>
        <test.1/>
        <test.2/>
        <test.3/>
    </test>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <executor>
        <executor.1/>
        <executor.2/>
        <executor.3/>
    </executor>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <invoker>
        <invoker.1/>
        <invoker.2/>
        <invoker.3/>
    </invoker>
    <recipient>
        <recipient.1/>
        <recipient.2/>
        <recipient.3/>
    </recipient>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
    <comment>
        <comment.1/>
        <comment.2/>
        <comment.3/>
    </comment>
</testExecution>

дает желаемый, правильный результат :

<testExecution>
   <test>
      <test.1/>
      <test.2/>
      <test.3/>
   </test>
   <comment>
      <comment.1/>
      <comment.2/>
      <comment.3/>
   </comment>
   <people>
      <importantPeople>
         <executor>
            <executor.1/>
            <executor.2/>
            <executor.3/>
         </executor>
         <comment>
            <comment.1/>
            <comment.2/>
            <comment.3/>
         </comment>
         <comment>
            <comment.1/>
            <comment.2/>
            <comment.3/>
         </comment>
      </importantPeople>
      <invoker>
         <invoker.1/>
         <invoker.2/>
         <invoker.3/>
      </invoker>
   </people>
   <recipient>
      <recipient.1/>
      <recipient.2/>
      <recipient.3/>
   </recipient>
   <comment>
      <comment.1/>
      <comment.2/>
      <comment.3/>
   </comment>
   <comment>
      <comment.1/>
      <comment.2/>
      <comment.3/>
   </comment>
</testExecution>
...