如何使用每个“列表项”的“标签”处理嵌套的“列表”

问题描述

在下面的示例中,我们尝试使用每个“list-item”的“label”处理嵌套的“LIST”:

标签示例:

style="ListNum1" 然后是 a.,b.,c.,... 等等
style="ListNum2" 然后 (1),(2),(3),... 等等
style="ListNum3" 然后 (a),(b),(c),... 等

谁能帮忙。

输入 XML:

<?xml version="1.0" encoding="UTF-8"?>
<body>
<list-item style="ListNum1"><p content-type="new">Your client may (<styled-content style="stat" style-type="Stat-Cal">Prob C &#x00a7;13659</styled-content>) because:</p></list-item>
<list-item style="ListNum2"><p content-type="new">For later income tax purposes</p></list-item>
<list-item style="ListNum3"><p content-type="new">Documents a &#x201c;stepped-up basis&#x201d; (<italic>i.e.,</italic> fair.</p></list-item>
<list-item style="ListNum3"><p content-type="new">Provides evidence for your client.</p></list-item>
<list-item style="ListNum2"><p content-type="new">If you or your <bold>client</bold>.</p></list-item>
<list-item style="ListNum1"><p content-type="new">If transfer <italic>unincorporated business</italic> appraisal. <styled-content style="stat" style-type="Stat-Cal">Prob C &#x00a7;13658</styled-content>.</p></list-item>
</body>

预期输出

<?xml version="1.0" encoding="UTF-8"?>
<body>
<list type="ListNum1">
<list-item style="ListNum1"><label>a.</label><p content-type="new">Your client may (<styled-content style="stat" style-type="Stat-Cal">Prob C &#x00a7;13659</styled-content>) because:</p></list-item>
<list type="ListNum2">
<list-item style="ListNum2"><label>(1)</label><p content-type="new">For later income tax purposes</p>
<list type="ListNum3">
<list-item style="ListNum3"><label>(a)</label><p content-type="new">Documents a &#x201c;stepped-up basis&#x201d; (<italic>i.e.,</italic> fair.</p></list-item>
<list-item style="ListNum3"><label>(b)</label><p content-type="new">Provides evidence for your client.</p></list-item>
</list></list-item>
<list-item style="ListNum2"><label>(2)</label><p content-type="new">If you or your <bold>client</bold>.</p></list-item>
</list></list-item>
<list-item style="ListNum1"><label>b.</label><p content-type="new">If transfer <italic>unincorporated business</italic> appraisal. <styled-content style="stat" style-type="Stat-Cal">Prob C &#x00a7;13658</styled-content>.</p></list-item>
</list>
</body>

XSLT 代码

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

<xsl:output indent="yes"/>

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

<xsl:template match="list-item[@style='ListNum1']">
    <xsl:if test="not(preceding-sibling::*[1][self::list-item[@style='ListNum1']])">
        <xsl:text disable-output-escaping="yes"><![CDATA[<list list-type="ListNum1">]]></xsl:text>
    </xsl:if>
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:copy>
    <xsl:if test="not(following-sibling::*[1][self::list-item[@style='ListNum1']])">
        <xsl:text disable-output-escaping="yes"><![CDATA[</list>]]></xsl:text>
    </xsl:if>
</xsl:template>

<xsl:template match="list-item[@style='ListNum2']">
    <xsl:if test="not(preceding-sibling::*[1][self::list-item[@style='ListNum2']])">
        <xsl:text disable-output-escaping="yes"><![CDATA[<list list-type="ListNum2">]]></xsl:text>
    </xsl:if>
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:copy>
    <xsl:if test="not(following-sibling::*[1][self::list-item[@style='ListNum2']])">
        <xsl:text disable-output-escaping="yes"><![CDATA[</list>]]></xsl:text>
    </xsl:if>
</xsl:template>

<xsl:template match="list-item[@style='ListNum3']">
    <xsl:if test="not(preceding-sibling::*[1][self::list-item[@style='ListNum3']])">
        <xsl:text disable-output-escaping="yes"><![CDATA[<list list-type="ListNum3">]]></xsl:text>
    </xsl:if>
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:copy>
    <xsl:if test="not(following-sibling::*[1][self::list-item[@style='ListNum3']])">
        <xsl:text disable-output-escaping="yes"><![CDATA[</list>]]></xsl:text>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

参考网址# https://xsltfiddle.liberty-development.net/93nwMoZ/1

解决方法

递归分组是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    expand-text="yes"
    exclude-result-prefixes="#all"
    version="3.0">
    
  <xsl:param name="format-map" as="map(xs:integer,xs:string)"
    select="map { 1 : 'a',2 : '1',3 : 'A' }"/>
    
  <xsl:function name="mf:group" as="node()*">
      <xsl:param name="items" as="element(list-item)*"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:where-populated>
          <list type="ListNum{$level}">
            <xsl:for-each-group select="$items" group-starting-with="list-item[@style = 'ListNum' || $level]">
                <xsl:copy>
                    <label>{format-integer(position(),$format-map($level))}</label>
                    <xsl:apply-templates select="node(),mf:group(tail(current-group()),$level + 1)"/>
                </xsl:copy>  
            </xsl:for-each-group>  
          </list>
      </xsl:where-populated>
  </xsl:function>

  <xsl:mode on-no-match="shallow-copy"/>

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

  <xsl:template match="body">
      <xsl:copy>
          <xsl:sequence select="mf:group(list-item,1)"/>
      </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

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

对于标签格式的详细信息,可以将其扩展为

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    expand-text="yes"
    exclude-result-prefixes="#all"
    version="3.0">
    
  <xsl:param name="format-map" as="map(xs:integer,3 : 'a' }"/>
    
  <xsl:function name="mf:format" as="xs:string">
      <xsl:param name="number" as="xs:integer"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:variable name="formatted-number"
        select="format-integer($number,$format-map($level))"/>
      <xsl:sequence
        select="if ($level = 1)
                then  $formatted-number || '.'
                else  '(' || $formatted-number || ')'"/>
  </xsl:function>
    
  <xsl:function name="mf:group" as="node()*">
      <xsl:param name="items" as="element(list-item)*"/>
      <xsl:param name="level" as="xs:integer"/>
      <xsl:where-populated>
          <list type="ListNum{$level}">
            <xsl:for-each-group select="$items" group-starting-with="list-item[@style = 'ListNum' || $level]">
                <xsl:copy>
                    <label>{mf:format(position(),$level)}</label>
                    <xsl:apply-templates select="node(),1)"/>
      </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ei5R4v4/1