XSLT - сортировка подмножества элементов из XML с сохранением несортированных элементов на их месте - PullRequest
0 голосов
/ 18 июня 2020

Я пытаюсь придумать XSLT, который будет сортировать элементы в XML ниже, сохраняя положение других элементов.

<TransactionSet TransactionSet_Id="12345">
<ATransaction ATransaction_Id="54321">
    <DoNotSort_1 DoNotSort_1_Id="90678">
        <SomeData/>
    </DoNotSort_1>
    <DoNotSort_2 DoNotSort_2_Id="46456">
        <OtherData/>
    </DoNotSort_2>
    <DoNotSort_3 DoNotSort_3_Id="33333"/>
    <SortIt SortIt_Id="11">
        <TheOrder>1</TheOrder>
        <MoreData/>
    </SortIt>
    <SortIt SortIt_Id="55">
        <TheOrder>5</TheOrder>
        <MoreData/>
    </SortIt>
    <SortIt SortIt_Id="22">
        <TheOrder>2</TheOrder>
        <MoreData/>
    </SortIt>
    <SortIt SortIt_Id="44">
        <TheOrder>4</TheOrder>
        <MoreData/>
    </SortIt>
    <DoNotSort_4 DoNotSort_4_Id="789456">
        <EvenMoreData/>
    </DoNotSort_4>
            <DoNotSort_4 DoNotSort_4_Id="899567">
        <EvenMoreData/>
    </DoNotSort_4>
            <DoNotSort_5 DoNotSort_5_Id="55555">
        <EvenMoreData/>
    </DoNotSort_5>
</ATransaction>

XSLT I применяется ниже:

<xsl:stylesheet 
    version="1.0" 
    xmlns="http://www.oneshield.com/DragonSchema" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:strip-space elements="*" />
    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="ATransaction">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates>
                <xsl:sort select= "TheOrder" data-type="number"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Результат XML Я получаю ниже:

<TransactionSet TransactionSet_Id="12345">
   <ATransaction ATransaction_Id="54321">
      <DoNotSort_1 DoNotSort_1_Id="90678">
         <SomeData/>
      </DoNotSort_1>
      <DoNotSort_2 DoNotSort_2_Id="46456">
         <OtherData/>
      </DoNotSort_2>
      <DoNotSort_3 DoNotSort_3_Id="33333"/>
      <DoNotSort_4 DoNotSort_4_Id="789456">
         <EvenMoreData/>
      </DoNotSort_4>
      <DoNotSort_4 DoNotSort_4_Id="899567">
         <EvenMoreData/>
      </DoNotSort_4>
      <DoNotSort_5 DoNotSort_5_Id="55555">
         <EvenMoreData/>
      </DoNotSort_5>
      <SortIt SortIt_Id="11">
         <TheOrder>1</TheOrder>
         <MoreData/>
      </SortIt>
      <SortIt SortIt_Id="22">
         <TheOrder>2</TheOrder>
         <MoreData/>
      </SortIt>
      <SortIt SortIt_Id="44">
         <TheOrder>4</TheOrder>
         <MoreData/>
      </SortIt>
      <SortIt SortIt_Id="55">
         <TheOrder>5</TheOrder>
         <MoreData/>
      </SortIt>
   </ATransaction>
</TransactionSet>

Моя проблема: даже если элементы отсортированы, элементы и были перемещены над элементами. Я хочу, чтобы они были на своем месте, под элементами.

Любая помощь в этом будет принята с благодарностью. Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 18 июня 2020

Если узлы, которые вы хотите отсортировать, всегда находятся в одном непрерывном блоке, вы можете просто:

XSLT 1.0

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

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

<xsl:template match="ATransaction">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates select="SortIt[1]/preceding-sibling::*"/>
        <xsl:apply-templates select="SortIt">
            <xsl:sort select= "TheOrder" data-type="number"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="SortIt[last()]/following-sibling::*"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
0 голосов
/ 18 июня 2020

В XSLT 2 или 3, предполагая, что вы хотите отсортировать соседние SortIt элементы, вы можете использовать for-each-group group-adjacent="boolean(self::SortIt)". В XSLT 1 вы можете попробовать использовать ключ для идентификации соседних SortIt, а затем обработать и отсортировать их вместе:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*"/>

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

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

  <xsl:template match="SortIt[preceding-sibling::*[1][self::SortIt]]"/>

  <xsl:template match="SortIt[not(preceding-sibling::*[1][self::SortIt])]">
      <xsl:for-each select=". | key('adjacent', generate-id())">
          <xsl:sort select="TheOrder" data-type="number"/>
          <xsl:copy-of select="."/>
      </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/a9HjZm

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...