XSLT 1.0 Переставить определенные записи потомков / детей на один уровень с родителями / предками - PullRequest
3 голосов
/ 12 августа 2011

Я ищу общий подход к перестановке некоторых конкретных потомков в уровень их узлов-предков.

Что важно:

  • Мне нужен общий шаблон, который работает для p и x.
  • Порядок узлов a b DEEPSPACENODE (сверху вниз) не должен изменяться в максимально возможной степени.

Мой вклад:

<root>
    <p>
        <a>1</a>
        <a>2</a>
        <a><DEEPSPACENODE/></a>
        <b>3</b>
        <b>4</b>
        <a>5</a>
        <a>6</a>
        <b>7</b>
    </p>

    <x>
        <a>8</a>
        <a>9</a>
        <b>10</b>
        <b>11</b>
        <a>12</a>
        <a>13</a>
        <b>14</b>
    </x>    
</root>

Мой желаемый вывод:

<root>
    <p>
        <a>1</a>
        <a>2</a>
        <a/>
    </p>
    <DEEPSPACENODE/>
    <b>3</b>
    <b>4</b>
    <p>
        <a>5</a>
        <a>6</a>
    </p>
    <b>7</b>

    <x>
        <a>8</a>
        <a>9</a>
    </x>
    <b>10</b>
    <b>11</b>
    <x>
        <a>12</a>
        <a>13</a>
    </x>
    <b>14</b>
</root>

Спасибо за вашу помощь. Я пытался решить это сам, но у меня ничего не получилось.

Ответы [ 2 ]

2 голосов
/ 12 августа 2011

Это более общее решение, которое может привести к желаемому результату без наложения каких-либо ограничений на документ XML - мы не предполагаем какого-либо предварительно определенного уровня вложенности или элемента с именем b присутствует:

<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="kFollowing"
   match="a[preceding-sibling::*[1]
                              [self::a]
           ]"
   use="concat(
         generate-id(
                preceding-sibling::*[not(self::a)][1]
                    ),
         generate-id(..)
               )
         "/>

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

 <xsl:template match="*[a]">
   <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match=
   "a[not(preceding-sibling::*[1][self::a])]">

   <xsl:variable name="vGroup" select=
   ".|key('kFollowing',
             concat(generate-id(preceding-sibling::*[1]),
                    generate-id(..)
                   )
          )"/>

   <xsl:element name="{name(..)}">
     <xsl:apply-templates mode="group"
     select="$vGroup"/>
   </xsl:element>

   <xsl:apply-templates select="$vGroup/*"/>
 </xsl:template>

 <xsl:template match="a" mode="group">
  <a>
   <xsl:apply-templates select="node()[not(self::*)]"/>
  </a>
 </xsl:template>

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

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

<root>
    <p>
        <a>1</a>
        <a>2</a>
        <a>
            <DEEPSPACENODE/>
        </a>
        <b>3</b>
        <b>4</b>
        <a>5</a>
        <a>6</a>
        <b>7</b>
    </p>
    <x>
        <a>8</a>
        <a>9</a>
        <b>10</b>
        <b>11</b>
        <a>12</a>
        <a>13</a>
        <b>14</b>
    </x>
</root>

желаемый, правильный результат получается :

<root>
   <p>
      <a>1</a>
      <a>2</a>
      <a/>
   </p>
   <DEEPSPACENODE/>
   <b>3</b>
   <b>4</b>
   <p>
      <a>5</a>
      <a>6</a>
   </p>
   <b>7</b>
   <x>
      <a>8</a>
      <a>9</a>
   </x>
   <b>10</b>
   <b>11</b>
   <x>
      <a>12</a>
      <a>13</a>
   </x>
   <b>14</b>
</root>

Теперь, с помощью следующего XML-документа, это решение все еще дает желаемый результат, в то время как решение @empo подавляет его :

<root>
   <c>
    <p>
        <a>1</a>
        <a>2</a>
        <a>
            <DEEPSPACENODE/>
        </a>
        <z>3</z>
        <z>4</z>
        <a>5</a>
        <a>6</a>
        <b>7</b>
    </p>
    <x>
        <a>8</a>
        <a>9</a>
        <b>10</b>
        <z>11</z>
        <a>12</a>
        <a>13</a>
        <b>14</b>
    </x>
  </c>  
</root>

То же преобразование при применении к XML-документу, приведенному выше, снова дает правильный желаемый результат :

<root>
   <c>
      <p>
         <a>1</a>
         <a>2</a>
         <a/>
      </p>
      <DEEPSPACENODE/>
      <z>3</z>
      <z>4</z>
      <p>
         <a>5</a>
         <a>6</a>
      </p>
      <b>7</b>
      <x>
         <a>8</a>
         <a>9</a>
      </x>
      <b>10</b>
      <z>11</z>
      <x>
         <a>12</a>
         <a>13</a>
      </x>
      <b>14</b>
   </c>
</root>

II.Решение XSLT 2.0 :

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

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

 <xsl:template match="*[a]">
  <xsl:for-each-group select="node()"
                      group-adjacent="name() eq 'a'">
    <xsl:apply-templates select="current-group()"
                         mode="group">
      <xsl:with-param name="pGroup"
                      select="current-group()"/>
    </xsl:apply-templates>
    <xsl:apply-templates select="current-group()[self::a]/*"/>
   </xsl:for-each-group>
  </xsl:template>

 <xsl:template match="a" mode="group"/>

 <xsl:template mode="group"
          match="a[not(preceding-sibling::*[1][self::a])]" >
   <xsl:param name="pGroup" as="node()*"/>

   <xsl:element name="{name(..)}">
     <xsl:apply-templates select="$pGroup" mode="shallow"/>
   </xsl:element>
 </xsl:template>

  <xsl:template match="a" mode="shallow">
    <a>
      <xsl:apply-templates select="node()[not(self::*)]"/>
    </a>
   </xsl:template>
</xsl:stylesheet>
2 голосов
/ 12 августа 2011

Проверьте эту таблицу стилей:

  • Сгруппируйте a элементов, проверив предшествующих братьев и сестер
  • Используйте смежные рекурсивные шаблоны для объединения групп a

ПРИМЕЧАНИЕ Я специально не управлял DEEPSPACENODE, потому что неясно, как вы хотите с этим справиться: P.Вы можете использовать это преобразование в качестве начальной точки.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="text()"/>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="*/*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="a[preceding-sibling::*[1][self::b]
        or not(preceding-sibling::*)]">
        <xsl:element name="{name(..)}">
            <xsl:apply-templates select="." mode="adjacent"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="b">
        <xsl:copy-of select="."/>
    </xsl:template>

    <xsl:template match="a" mode="adjacent">
        <a>
            <xsl:value-of select="self::node()[not(DEEPSPACENODE)]"/>
        </a>
        <xsl:apply-templates select="
            following-sibling::*[1][self::a]" mode="adjacent"/>
    </xsl:template>

</xsl:stylesheet>

с выводом:

<root>
   <p>
      <a>1</a>
      <a>2</a>
      <a/>
   </p>
   <b>3</b>
   <b>4</b>
   <p>
      <a>5</a>
      <a>6</a>
   </p>
   <b>7</b>
   <x>
      <a>8</a>
      <a>9</a>
   </x>
   <b>10</b>
   <b>11</b>
   <x>
      <a>12</a>
      <a>13</a>
   </x>
   <b>14</b>
</root>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...