增强 XSL 以从平面树问题创建嵌套列表

发布于 2024-10-22 23:19:30 字数 1875 浏览 0 评论 0原文

我问了一个非常类似的问题([1]: XSL 创建扁平树问题的嵌套列表“从扁平树问题创建嵌套列表”)不久前,但我的问题略有扩大。最初我没有考虑列表中嵌套的段落。所以现在,输入:

<root>
    <h1>text</h1>
    <list level="1">num1</list>
    <list level="1">num2</list>
    <para type="indent">indented para1</para>
    <list level="2">sub-num1</list>
    <para type="indent">sub-indented para1</para>
    <para type="indent">sub-indented para2</para>
    <list level="2">sub-num2</list>
    <list level="3">sub-sub-num1</list>
    <list level="1">num3</list>
    <p>text</p>
    <list>num1</list>
    <list>num2</list>
    <h2>text</h2>
</root>

我需要这个输出:

<root>
    <h1>text</h1>
    <ol>
        <li>num1</li>
        <li>num2
            <paragraph>indented para1</paragraph>
            <ol>
                <li>sub-num1
                    <paragraph>sub-indented para1</paragraph>
                    <paragraph>sub-indented para2</paragraph>
                </li>
                <li>sub-num2                     
                    <ol>
                        <li>sub-sub-num1</li>
                    </ol>
                </li>
            </ol>
        </li>
        <li>num3</li>
    </ol>
    <p>text</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <h2>text</h2>
</root>

也可能有缩进段落的实例不在列表中,但我想一旦我把这只猴子从我的背上拿下来我就可以弄清楚。 我需要使用 XSLT 1.0,再次感谢您的帮助。

I asked a very similar question ([1]: XSL to create nested list from flat tree problem "Create nested list from flat tree problem") a while ago, but my problem has expanded slightly. Originally I did not take into account paragraphs nested within lists. So now, with an input of:

<root>
    <h1>text</h1>
    <list level="1">num1</list>
    <list level="1">num2</list>
    <para type="indent">indented para1</para>
    <list level="2">sub-num1</list>
    <para type="indent">sub-indented para1</para>
    <para type="indent">sub-indented para2</para>
    <list level="2">sub-num2</list>
    <list level="3">sub-sub-num1</list>
    <list level="1">num3</list>
    <p>text</p>
    <list>num1</list>
    <list>num2</list>
    <h2>text</h2>
</root>

I need this output:

<root>
    <h1>text</h1>
    <ol>
        <li>num1</li>
        <li>num2
            <paragraph>indented para1</paragraph>
            <ol>
                <li>sub-num1
                    <paragraph>sub-indented para1</paragraph>
                    <paragraph>sub-indented para2</paragraph>
                </li>
                <li>sub-num2                     
                    <ol>
                        <li>sub-sub-num1</li>
                    </ol>
                </li>
            </ol>
        </li>
        <li>num3</li>
    </ol>
    <p>text</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <h2>text</h2>
</root>

There may also be instances of indented paragraph that are not within a list, but I think I can figure that out once I've got this monkey off my back.
I need to use XSLT 1.0, and once again, any help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萤火眠眠 2024-10-29 23:19:30

无需对我之前的答案进行太多修改,此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kListByParent"
             match="list"
             use="concat(generate-id(
                            preceding-sibling::*[
                               not(self::list|self::para)
                            ][1]
                         ), '+',
                         generate-id(
                            preceding-sibling::list[
                               current()/@level > @level
                            ][1]
                         )
                  )"/>
    <xsl:key name="kParaByList" match="para"
             use="generate-id(preceding-sibling::list[1])"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node()|@*" mode="copy">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="list[preceding-sibling::*[1][
                                 self::list|self::para
                              ]
                         ] |
                         para"/>
    <xsl:template match="list">
        <xsl:variable name="vListMark"
                      select="generate-id(preceding-sibling::*[1])"/>
        <ol>
            <xsl:apply-templates select="key('kListByParent',
                                             concat($vListMark,'+'))"
                                 mode="makeLi">
                <xsl:with-param name="pListMark" select="$vListMark"/>
            </xsl:apply-templates>
        </ol>
    </xsl:template>
    <xsl:template match="list" mode="makeLi">
        <xsl:param name="pListMark"/>
        <xsl:variable name="vSubList"
                      select="key('kListByParent',
                                  concat($pListMark,'+',generate-id()))"/>
        <li>
            <xsl:apply-templates
                 select="node()|key('kParaByList',generate-id())"
                 mode="copy"/>
            <xsl:if test="$vSubList">
                <ol>
                    <xsl:apply-templates select="$vSubList" mode="makeLi">
                        <xsl:with-param name="pListMark"
                                        select="$pListMark"/>
                    </xsl:apply-templates>
                </ol>
            </xsl:if>
        </li>
    </xsl:template>
</xsl:stylesheet>

输出:

<root>
    <h1>text</h1>
    <ol>
        <li>num1</li>
        <li>num2
            <para type="indent">indented para1</para>
            <ol>
                <li>sub-num1
                    <para type="indent">sub-indented para1</para>
                    <para type="indent">sub-indented para2</para>
                </li>
                <li>sub-num2
                    <ol>
                        <li>sub-sub-num1</li>
                    </ol>
                </li>
            </ol>
        </li>
        <li>num3</li>
    </ol>
    <p>text</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <h2>text</h2>
</root>

注意:从概念上讲,这应该list开头且最小@level递归分组>。我将重构它以使其在语义上更加准确。

编辑:语义上更接近的 XSLT 2.0 解决方案。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="root">
        <xsl:copy>
            <xsl:for-each-group select="node()"
                 group-adjacent="boolean(self::list|self::para)">
                <xsl:choose>
                    <xsl:when test="current-grouping-key()">
                        <xsl:call-template name="makeList">
                            <xsl:with-param name="pList"
                                            select="current-group()"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    <xsl:template name="makeList">
        <xsl:param name="pList"/>
        <xsl:variable name="vFirstList" select="($pList/self::list)[1]"/>
        <xsl:apply-templates
             select="$pList[not(. >> $vFirstList)] except $vFirstList"/>
        <xsl:if test="$vFirstList">
            <ol>
                <xsl:for-each-group select="$pList[not($vFirstList >> .)]"
                 group-starting-with="list[not($vFirstList/@level ne @level)]">
                    <li>
                        <xsl:value-of select="current-group()[1]"/>
                        <xsl:if test="current-group()[2]">
                            <xsl:call-template name="makeList">
                                <xsl:with-param name="pList"
                                 select="current-group()[position()!=1]"/>
                            </xsl:call-template>
                        </xsl:if>
                    </li>
                </xsl:for-each-group>
            </ol>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Without too much modifications to my previus answer, this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kListByParent"
             match="list"
             use="concat(generate-id(
                            preceding-sibling::*[
                               not(self::list|self::para)
                            ][1]
                         ), '+',
                         generate-id(
                            preceding-sibling::list[
                               current()/@level > @level
                            ][1]
                         )
                  )"/>
    <xsl:key name="kParaByList" match="para"
             use="generate-id(preceding-sibling::list[1])"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node()|@*" mode="copy">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="list[preceding-sibling::*[1][
                                 self::list|self::para
                              ]
                         ] |
                         para"/>
    <xsl:template match="list">
        <xsl:variable name="vListMark"
                      select="generate-id(preceding-sibling::*[1])"/>
        <ol>
            <xsl:apply-templates select="key('kListByParent',
                                             concat($vListMark,'+'))"
                                 mode="makeLi">
                <xsl:with-param name="pListMark" select="$vListMark"/>
            </xsl:apply-templates>
        </ol>
    </xsl:template>
    <xsl:template match="list" mode="makeLi">
        <xsl:param name="pListMark"/>
        <xsl:variable name="vSubList"
                      select="key('kListByParent',
                                  concat($pListMark,'+',generate-id()))"/>
        <li>
            <xsl:apply-templates
                 select="node()|key('kParaByList',generate-id())"
                 mode="copy"/>
            <xsl:if test="$vSubList">
                <ol>
                    <xsl:apply-templates select="$vSubList" mode="makeLi">
                        <xsl:with-param name="pListMark"
                                        select="$pListMark"/>
                    </xsl:apply-templates>
                </ol>
            </xsl:if>
        </li>
    </xsl:template>
</xsl:stylesheet>

Output:

<root>
    <h1>text</h1>
    <ol>
        <li>num1</li>
        <li>num2
            <para type="indent">indented para1</para>
            <ol>
                <li>sub-num1
                    <para type="indent">sub-indented para1</para>
                    <para type="indent">sub-indented para2</para>
                </li>
                <li>sub-num2
                    <ol>
                        <li>sub-sub-num1</li>
                    </ol>
                </li>
            </ol>
        </li>
        <li>num3</li>
    </ol>
    <p>text</p>
    <ol>
        <li>num1</li>
        <li>num2</li>
    </ol>
    <h2>text</h2>
</root>

Note: Conceptually this should be recursively grouping starting with list with minimum @level. I will refactor this to make it more semantically accurate.

EDIT: More semantically closer XSLT 2.0 solution.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="root">
        <xsl:copy>
            <xsl:for-each-group select="node()"
                 group-adjacent="boolean(self::list|self::para)">
                <xsl:choose>
                    <xsl:when test="current-grouping-key()">
                        <xsl:call-template name="makeList">
                            <xsl:with-param name="pList"
                                            select="current-group()"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    <xsl:template name="makeList">
        <xsl:param name="pList"/>
        <xsl:variable name="vFirstList" select="($pList/self::list)[1]"/>
        <xsl:apply-templates
             select="$pList[not(. >> $vFirstList)] except $vFirstList"/>
        <xsl:if test="$vFirstList">
            <ol>
                <xsl:for-each-group select="$pList[not($vFirstList >> .)]"
                 group-starting-with="list[not($vFirstList/@level ne @level)]">
                    <li>
                        <xsl:value-of select="current-group()[1]"/>
                        <xsl:if test="current-group()[2]">
                            <xsl:call-template name="makeList">
                                <xsl:with-param name="pList"
                                 select="current-group()[position()!=1]"/>
                            </xsl:call-template>
                        </xsl:if>
                    </li>
                </xsl:for-each-group>
            </ol>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文