XML 平面编号索引到真实树结构 - XSLT

问题描述 投票:0回答:1

XML 平面编号索引到真实树结构 - XSLT

我正在尝试制作一个索引树,其中编号部分在逻辑上相互嵌套。我正在使用 XSLT

2.0 并且一直在尝试使用 for-each-group ... group-starting-with 收效甚微。

这是一个示例输入 XML:

<DOC>
  <section class="AB">
    <h1>Real section header</h1>
    <p><b>1. heading</b></p>
    <p>Some text here.</p>
    <p>More text.</p>
    <p><b>1.1. setting</b></p>
    <p>More words.</p>
    <p><b>1.2. fremmer</b></p>
    <p><b>1.2.1. point</b></p>
    <p>We are sailing.</p>
    <p>Whisky in the jar.</p>
    <p><b>1.2.2.</b></p>
    <p>Johnny is the man.</p>
    <p><b>1.2.3.</b></p>
    <p>And we go on and on.</p>
    <ul>
      <li>List item one</li>
      <li>List item two</li>
      <li>List item three</li>
    </ul>
    <p><b>2. Another heading</b></p>
    <p>Here is the accompanying text.</p>
    <table>
      <tr>
        <td>1</td>
        <td>Bla bla bla.</td>
      </tr>
      <tr>
        <td>2</td>
        <td>BlaX bla bla.</td>
      </tr>
      <tr>
        <td>3</td>
        <td>BlaY bla bla.</td>
      </tr>
    </table>
    <p><b>3. Last heading</b></p>
    <p>Here is the accompanying text right now.</p>
  </section>
</DOC>

这就是输出应该是什么:

<DOC>
  <section class="AB">
    <h1>Real section header</h1>
    <section>
      <h1>1. heading</h1>
      <p>Some text here.</p>
      <p>More text.</p>
      <section>
        <h1>1.1. setting</h1>
        <p>More words.</p>
      </section>
      <section>
        <h1>1.2. fremmer</h1>
        <section>
          <h1>1.2.1. underpunkt</h1>
          <p>We are sailling.</p>
          <p>Whisky in the jar.</p>
        </section>
        <section>
          <h1>1.2.2.</h1>
          <p>Johnny is the man.</p>
        </section>
        <section>
          <h1>1.2.3.</h1>
          <p>And we go on and on.</p>
          <ul>
            <li>List item one</li>
            <li>List item two</li>
            <li>List item three</li>
          </ul>
        </section>
      </section>
    </section>
    <section>
      <h1>2. Another heading</h1>
      <p>Here is the accompanying text.</p>
      <table>
        <tr>
          <td>1</td>
          <td>Bla bla bla.</td>
        </tr>
        <tr>
          <td>2</td>
          <td>BlaX bla bla.</td>
        </tr>
        <tr>
          <td>3</td>
          <td>BlaY bla bla.</td>
        </tr>
      </table>
    </section>
    <section>
      <h1>3. Last heading</h1>
      <p>Here is the accompanying text right now.</p>
    </section>
  </section>
</DOC>

tree xslt-2.0
1个回答
0
投票

最后,您的输入似乎不太符合我评论的建议,因为内部

p/b
s在标题编号后没有空格和文本,但您当然可以使用不同的测试,例如

<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"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:function name="mf:group" as="node()*">
    <xsl:param name="nodes" as="node()*"/>
    <xsl:param name="level" as="xs:integer"/>
    <xsl:for-each-group select="$nodes" group-starting-with="p[b[string-length(translate(replace(., '^([0-9.]+)[^0-9.]*$', '$1'), '0123456789', '')) = $level]]">
      <xsl:choose>
        <xsl:when test="self::p[b[string-length(translate(replace(., '^([0-9.]+)[^0-9.]*$', '$1'), '0123456789', '')) = $level]]">
          <section>
            <xsl:apply-templates select="."/>
            <xsl:sequence select="mf:group(tail(current-group()), $level + 1)"/>
          </section>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="current-group()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:function>

  <xsl:template match="section[p/b]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:sequence select="mf:group(node(), 1)"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="section/p[b]">
    <h1>
      <xsl:apply-templates/>
    </h1>
  </xsl:template>
  
  <xsl:template match="section/p/b">
    <xsl:apply-templates/>
  </xsl:template>
  
  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes" html-version="5"/>
  <xsl:strip-space elements="*"/>

</xsl:stylesheet>

那是 XSLT 3,对于 XSLT 2.0,您需要拼出

xsl:mode
声明,例如

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

并使用

subsequence(current-group(), 2)
代替
tail(current-group())
.

© www.soinside.com 2019 - 2024. All rights reserved.