Как переместить элемент li в предыдущий элемент ‘p’ — XSLT

#xslt #xslt-2.0

#xslt #xslt-2.0

Вопрос:

Если следующий li элемент-элемент-брат p , то как переместить li элемент?
Ввод

 <root>
<p>start</p>
<p>aaaaa</p>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
<p>aaaaa</p>
<p>aaaaaa</p>
  

** Ожидаемый результат**

 <root>
<p>start</p>
<p>aaaaa
    <li>aaa</li>
    <li>bbb</li>
    <li>ccc</li>
</p>
<p>aaaaa</p>
<p>aaaaaa</p>
  

XSLT:

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

<xsl:template match="p">
    <p>
        <xsl:apply-templates/>
        <xsl:if test="following-sibling::*[1][self::li]">
            <xsl:for-each select="following-sibling::*[1][self::li]">
                <li><xsl:value-of select="."/></li>
            </xsl:for-each>
        </xsl:if>
    </p>
</xsl:template>
  

Комментарии:

1. Почему в вашем шаблоне создан узел «al»? Я не вижу ни одного узла «al» в вашем требуемом выводе.

2. @Себастьян, я отредактировал свой вопрос, пожалуйста, проверьте

Ответ №1:

Поскольку вы можете использовать XSLT-2.0, вы можете использовать xsl:for-each-group . Итак, ниже приведен один из способов достижения желаемого результата:

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

    <xsl:template match="@* | node()">
      <xsl:copy>
        <xsl:apply-templates select="@* | node()" />
      </xsl:copy>
    </xsl:template>
  
    <xsl:template match="p[name(following-sibling::*[1]) = 'li']">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
            <xsl:for-each-group select="following-sibling::*" group-adjacent="name()">
                <xsl:if test="position()=1">
                    <xsl:copy-of select="current-group()" />
                </xsl:if>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
  
    <xsl:template match="li[preceding-sibling::*[1] = (preceding-sibling::p[1] | preceding-sibling::li[1])]" />
  
</xsl:stylesheet>
  

Вывод:

 <?xml version="1.0" encoding="UTF-8"?>
<root>
   <p>start</p>
   <p>aaaaa<li>aaa</li>
      <li>bbb</li>
      <li>ccc</li>
   </p>
   <p>aaaaa</p>
   <p>aaaaaa</p>
</root>
  

Комментарии:

1. Сэр, @zx485 Спасибо за ответ. Можете ли вы проверить последние 2 залога, если элемент li не предшествует элементу-родственному элементу p, тогда не удаляйте элемент li ( xsltfiddle. liberty-development.net/nb9NXUL/2 ).

2. Спасибо, сэр, дайте мне решение!

Ответ №2:

Похоже, вы просто хотите

   <xsl:template match="root">
      <xsl:copy>
          <xsl:for-each-group select="*" group-starting-with="p">
              <xsl:copy>
                  <xsl:apply-templates select="node(), tail(current-group())"/>
              </xsl:copy>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>
  

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

tail Функция не будет поддерживаться процессором XSLT 2, но, конечно current-group()[position() gt 1] , может быть использована вместо этого.

Комментарии:

1. Сэр, пожалуйста, проверьте последнюю строку, если отредактируйте мое изменение последнего элемента ввода, тогда не следует переходить к предыдущему элементу. ( xsltfiddle. liberty-development.net/pNvt6XN/1 )

2. @Sam, подумайте о том, чтобы отредактировать свой вопрос с учетом имеющихся у вас входных данных и желаемых выходных данных.

Ответ №3:

Вот способ, которым вы могли бы это сделать, который также работал бы в XSLT 1.0.

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

  <xsl:output method="xml" indent="yes"/>

  <!-- P node that has a li node directly below it -->
  <xsl:template match="p[following-sibling::*[1][self::li]]">
      <xsl:variable name="id" select="generate-id(.)"/>
      <xsl:copy>
        <xsl:value-of select="."/>
        <!-- Copy all li nodes that share the same p as their preceding-sibling -->
        <xsl:copy-of select="following-sibling::li[generate-id(preceding-sibling::p[1]) = $id]"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="li"/>
  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>
  

Посмотрите, как это работает здесь: https://xsltfiddle .liberty-development.net/nb9NXUL/3

Комментарии:

1. Спасибо за ответ. Можете ли вы проверить последние 2 залога, если элемент li не предшествует элементу-родственному элементу p, тогда не удаляйте элемент li ( xsltfiddle. liberty-development.net/nb9NXUL/1 ).