如何将 li 元素移动到前一个兄弟 'p' 元素中 - XSLT

How to li element move into the preceding-sibling 'p' element - XSLT

如果 p 的跟随兄弟 li 元素,那么如何移动 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>

因为可以使用 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>

这是一种可以在 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

看来你只是想要

  <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

XSLT 2 处理器不支持 tail 函数,但当然可以使用 current-group()[position() gt 1]