XSLT перемещение предметов внутри другого тега на том же уровне - PullRequest
3 голосов
/ 26 сентября 2011

У меня есть эта проблема для xslt:

Это входной файл:

  <root>
   <header/>
   <item/>
   … other n-1 <item/>
   <header/>
   <item/>
   … other m-1 <item/>
  </root>

, поэтому заголовок и элемент находятся на одном уровне (/ root).он должен быть преобразован во что-то вроде:

<root2>
  <header2>
     <item2/>
     …<item2/> // the first n-items up
  </header2>
  <header2>
     <item2/>
     …<item2/> // the last m-items up
  </header2>
</root2>

, поэтому в основном первый n-элемент должен быть перемещен в первом заголовке, а вторая группа элементов должна быть перемещена во втором заголовке.Любая идея, как получить это?

Спасибо

Рандомизировать

Ответы [ 2 ]

1 голос
/ 26 сентября 2011

Пример XML:

<root>
    <header/>
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <header/>
    <item>5</item>
    <item>6</item>
    <item>7</item>
</root>

XSLT с использованием группировки:

<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="k" match="item" use="count(preceding-sibling::header)"/>

    <xsl:template match="/">
        <root2>
            <xsl:apply-templates select="root/item[generate-id(.) = generate-id(key('k', count(preceding-sibling::header)))]" mode="a"/>
        </root2>
    </xsl:template>

    <xsl:template match="item" mode="a">
        <header2>
            <xsl:apply-templates select="key('k', count(preceding-sibling::header))"/>
        </header2>
    </xsl:template>

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

</xsl:stylesheet>

Или простой конкретный XSLT:

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

    <xsl:template match="/">
        <root2>
            <header2>
                <xsl:apply-templates select="root/item[count(preceding-sibling::header) = 1]"/>
            </header2>
            <header2>
                <xsl:apply-templates select="root/item[count(preceding-sibling::header) = 2]"/>
            </header2>
        </root2>
    </xsl:template>

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

</xsl:stylesheet>

Оба выдают одинаковый вывод:

<root2>
  <header2>
    <item>1</item>
    <item>2</item>
    <item>3</item>
  </header2>
  <header2>
    <item>5</item>
    <item>6</item>
    <item>7</item>
  </header2>
</root2>
0 голосов
/ 27 сентября 2011

Это более простое и эффективное решение XSLT 1.0, чем подсчет всех предыдущих братьев и сестер :

<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="kFollowing" match="item"
  use="generate-id(preceding-sibling::header[1])"/>

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

 <xsl:template match="header">
  <heather2>
   <xsl:copy-of select="key('kFollowing', generate-id())"/>
  </heather2>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к следующему документу XML :

<root>
    <header/>
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <header/>
    <item>5</item>
    <item>6</item>
    <item>7</item>
</root>

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

<root>
   <heather2>
      <item>1</item>
      <item>2</item>
      <item>3</item>
   </heather2>
   <heather2>
      <item>5</item>
      <item>6</item>
      <item>7</item>
   </heather2>
</root>

Пояснение :

Ключопределяется таким образом, что для header любой из следующих непосредственно за item элементов соответствует generate-id() этого header.

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:template match="/*">
  <root>
   <xsl:for-each-group select="item"
        group-adjacent=
         "generate-id(preceding-sibling::header[1])">
     <header2>
      <xsl:sequence select="current-group()"/>
     </header2>
   </xsl:for-each-group>
  </root>
 </xsl:template>
</xsl:stylesheet>

, когда это преобразование применяется к тому же XML-документу (см. Выше), получается тот же правильный результат :

<root>
   <header2>
      <item>1</item>
      <item>2</item>
      <item>3</item>
   </header2>
   <header2>
      <item>5</item>
      <item>6</item>
      <item>7</item>
   </header2>
</root>

Пояснение : Использование xsl:for-each-group, group-adjacent, current-group()

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