在 XSLT 中对节点属性进行排序并保持结构

发布于 2024-11-10 11:10:50 字数 1388 浏览 0 评论 0原文

我有以下问题。我花了两天时间寻找解决方案,但找不到。

我有一个具有不常见级别属性的列表(列表仅用 GDocs 中的边距表示),并且我想重新级别(排序)节点而不重构 XML。

我的输入:

<lists>
  <list margin="10">1</list>
  <list margin="15">2</list>
  <somethingelse/>
  <list margin="33">3</list>
  <list margin="72">4</list>
  <list margin="15">5</list>
  <list margin="64">6</list>
  <list margin="72">7</list>
</lists>

这个输出没问题:

<lists>
  <list level="1">1</list>
  <list level="2">2</list>
  <somethingelse/>
  <list level="1">3</list>
  <list level="3">4</list> 
  <list level="1">5</list>
  <list level="2">6</list>
  <list level="3">7</list>
</lists>

我想要的输出(两个节点之间的级别差应该仅为 1)

<lists>
  <list level="1">1</list>
  <list level="2">2</list>
  <somethingelse/>
  <list level="1">3</list>
  <list level="2">4</list>
  <list level="1">5</list>
  <list level="2">6</list>
  <list level="3">7</list>
</lists>

这也可以用 XSLT 1.0 来实现吗?

I have following problem. I worked two days on a solution but I cannot find one.

I have a list with uncommon level-attribute (lists are only represented with margins in GDocs) and I want to re-level (sort) the nodes without restructuring the XML.

My input:

<lists>
  <list margin="10">1</list>
  <list margin="15">2</list>
  <somethingelse/>
  <list margin="33">3</list>
  <list margin="72">4</list>
  <list margin="15">5</list>
  <list margin="64">6</list>
  <list margin="72">7</list>
</lists>

This output would be ok:

<lists>
  <list level="1">1</list>
  <list level="2">2</list>
  <somethingelse/>
  <list level="1">3</list>
  <list level="3">4</list> 
  <list level="1">5</list>
  <list level="2">6</list>
  <list level="3">7</list>
</lists>

My desired output (level difference between two nodes should only be 1)

<lists>
  <list level="1">1</list>
  <list level="2">2</list>
  <somethingelse/>
  <list level="1">3</list>
  <list level="2">4</list>
  <list level="1">5</list>
  <list level="2">6</list>
  <list level="3">7</list>
</lists>

Is this also possible to do with XSLT 1.0 ?

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

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

发布评论

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

评论(1

妄司 2024-11-17 11:10:50

看来我自己回答了我的问题。这是解决方案。请记住,两个列表之间的级别差异最大为 +-1。

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

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

<!-- find every list element which has a preceding non-list element -->
<xsl:template match="list[not(preceding-sibling::*[1][self::list])]">
        <!-- now walk recursive through all lists -->
        <xsl:apply-templates select="self::list" mode="recurse">
            <xsl:with-param name="level1_margin" select="@margin"/>
            <xsl:with-param name="level" select="1"/>
       </xsl:apply-templates> 
</xsl:template>

<!-- remove other list elements, because they are recursive processed -->
<xsl:template match="list"/>

<!-- remove @margin from list -->
<xsl:template match="list/@margin"/>

<!-- go recursive through all following lists -->
<xsl:template match="list" mode="recurse">
    <xsl:param name="level1_margin" select="0"/>
    <xsl:param name="level" select="1"/>

    <xsl:variable name="nextStep" select="self::list/following-sibling::*[1][self::list]"/>

    <!-- create current list element with its level -->
    <xsl:apply-templates select="self::list" mode="create">
        <xsl:with-param name="level" select="$level"/>
    </xsl:apply-templates>

    <xsl:if test="$nextStep">
        <xsl:choose>
            <!-- new start margin/point for level 1 -->
            <xsl:when test="($nextStep/@margin <= $level1_margin) or ($nextStep/@margin < @margin and $level = 2)">
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$nextStep/@margin"/>
                    <xsl:with-param name="level" select="1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- -1 -->
            <xsl:when test="$nextStep/@margin < @margin and $level > 1">
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$level1_margin"/>
                    <xsl:with-param name="level" select="$level - 1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- +1 -->
            <xsl:when test="$nextStep/@margin > @margin">
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$level1_margin"/>
                    <xsl:with-param name="level" select="$level + 1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- +-0 -->
            <xsl:otherwise>
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$level1_margin"/>
                    <xsl:with-param name="level" select="$level"/>
                </xsl:apply-templates>
            </xsl:otherwise>                                    
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- create list element with level attribute -->
<xsl:template match="list" mode="create">
    <xsl:param name="level"/>
    <list>
        <xsl:attribute name="level">
            <xsl:value-of select="$level"/>
        </xsl:attribute>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates/>
    </list>
</xsl:template>

It seems I answer my question myself. Here is the solution. Keep in mind that the level difference between two lists will be maximum +-1.

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

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

<!-- find every list element which has a preceding non-list element -->
<xsl:template match="list[not(preceding-sibling::*[1][self::list])]">
        <!-- now walk recursive through all lists -->
        <xsl:apply-templates select="self::list" mode="recurse">
            <xsl:with-param name="level1_margin" select="@margin"/>
            <xsl:with-param name="level" select="1"/>
       </xsl:apply-templates> 
</xsl:template>

<!-- remove other list elements, because they are recursive processed -->
<xsl:template match="list"/>

<!-- remove @margin from list -->
<xsl:template match="list/@margin"/>

<!-- go recursive through all following lists -->
<xsl:template match="list" mode="recurse">
    <xsl:param name="level1_margin" select="0"/>
    <xsl:param name="level" select="1"/>

    <xsl:variable name="nextStep" select="self::list/following-sibling::*[1][self::list]"/>

    <!-- create current list element with its level -->
    <xsl:apply-templates select="self::list" mode="create">
        <xsl:with-param name="level" select="$level"/>
    </xsl:apply-templates>

    <xsl:if test="$nextStep">
        <xsl:choose>
            <!-- new start margin/point for level 1 -->
            <xsl:when test="($nextStep/@margin <= $level1_margin) or ($nextStep/@margin < @margin and $level = 2)">
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$nextStep/@margin"/>
                    <xsl:with-param name="level" select="1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- -1 -->
            <xsl:when test="$nextStep/@margin < @margin and $level > 1">
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$level1_margin"/>
                    <xsl:with-param name="level" select="$level - 1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- +1 -->
            <xsl:when test="$nextStep/@margin > @margin">
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$level1_margin"/>
                    <xsl:with-param name="level" select="$level + 1"/>
                </xsl:apply-templates>
            </xsl:when>
            <!-- +-0 -->
            <xsl:otherwise>
                <xsl:apply-templates select="$nextStep" mode="recurse">
                    <xsl:with-param name="level1_margin" select="$level1_margin"/>
                    <xsl:with-param name="level" select="$level"/>
                </xsl:apply-templates>
            </xsl:otherwise>                                    
        </xsl:choose>
    </xsl:if>
</xsl:template>

<!-- create list element with level attribute -->
<xsl:template match="list" mode="create">
    <xsl:param name="level"/>
    <list>
        <xsl:attribute name="level">
            <xsl:value-of select="$level"/>
        </xsl:attribute>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates/>
    </list>
</xsl:template>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文