xml - 从两个 xml 文件在 XSLT 中排序

标签 xml xslt xpath xslt-2.0

我有这两个xml 1> 默认.xml

<UI-defination>
   <class >
      <list_view >
         <members>
            <member col_span="1" name="code" displayName="Code"/>
            <member col_span="1" name="creationTS" displayName="CreationTS"/>
            <member col_span="1" name="creator" displayName="Creator"/>
            <member col_span="1" name="displayName" displayName="DisplayName"/>
            <member col_span="1" name="emailAddress" displayName="EmailAddress"/>
            <member col_span="1" name="id" displayName="Id"/>
         </members>
      </list_view>
   </class>
</UI-defination>

2>规则.xml

<UI-defination>
    <class name="Role">
        <list_view multiselect="true">
            <members>
                <member name="displayName" sequence="3"/>
                <member name="code" sequence="4"/>
            </members>
            <exclude>
                <members>
                    <member name="id"/>
                    <member name="creator"/>
                </members>
            </exclude>
       </list_view>
    </class>
</UI-defination>

我想按照以下规则显示成员元素的列表

  • rules.xml/members/member 应该从列表中排除
  • 元素应该根据rules.xml中的sequence属性得到显示
  • 那些不在 rules.xml/members/member 中的元素应该按照它们在 default.xml 中的自然顺序显示。
    预期输出是……

    创作TS
    电子邮件地址
    显示名称
    代码

最佳答案

Then the elements which has sequence attr, they should be at that exact position. Then void position should get filled by the natural order of remaining element.(i.e. by the elements which don't have sequence attr., from default.xml)

恕我直言,这不是排序问题,而是排队问题。
让我们通过两种类型的成员来简化示例:放置成员,其在队列中的位置被保留,以及需要填补放置成员之间的空隙的普通成员。

<members>
    <member id="1" place="9"/>
    <member id="2" place="2"/>
    <member id="3" place="5"/>
    <member id="4"/>
    <member id="5"/>
    <member id="6"/>
    <member id="7"/>
    <member id="8"/>
    <member id="9"/>
    <member id="10"/>
    <member id="11"/>
    <member id="12"/>
</members>

排队算法可以描述如下:

  1. 保留成员按保留位置排序。

  2. 每个保留的成员“调用”一组普通成员坐在它前面。

    在我们的示例中,我们在位置 2、5 和 9 保留了成员。之前 把预留的成员安排在 9 号位,我们需要召集 3 人一组 普通成员(member)在6、7、8位就座。

    这个组的大小等于 现任成员(member)预留名额及其前任名额 保留兄弟。在我们的例子中是 9 - 5 - 1 = 3。

    这个组的起始位置可以推导如下:因为 前一个成员的预留位置是#5,那么5个成员有 已经就座;其中,2名成员(在#2和#5位置) 是保留成员(member),所以只有3个普通成员(member) 坐下,我们小组从位置 5 - 3 + 1 = 4 开始。

  3. 最后一个预定的成员(member)叫其他普通成员(member)在他后面坐。

这是 XSLT 1.0 中的一个实现示例:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="reserved-members">
    <xsl:for-each select="/members/member[@place]">
        <xsl:sort select="@place" data-type="number" order="ascending"/>
        <xsl:copy-of select="."/>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="ordinary-members" select="/members/member[not(@place)]"/>

<xsl:template match="/">
    <output>
        <xsl:for-each select="exsl:node-set($reserved-members)/member">

            <xsl:variable name="previous-place"> 
                <xsl:choose>
                    <xsl:when test="position()>1">
                        <xsl:value-of select="preceding-sibling::member[1]/@place"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="0"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

            <xsl:variable name="gap-size" select="@place - $previous-place - 1"/>
            <xsl:variable name="gap-start" select="$previous-place - count(preceding-sibling::member) + 1"/> 

            <!-- fill the gap with ordinary members -->
            <xsl:for-each select="$ordinary-members[$gap-start &lt;= position() and position() &lt; $gap-start + $gap-size]">
                <xsl:copy-of select="."/>
            </xsl:for-each>

            <!-- output the reserved member -->
            <member id="{@id}" place="{@place}" start="{$gap-start}" size="{$gap-size}"/>

            <!-- output remaining ordinary members -->
            <xsl:if test="position()=last()">
                <xsl:for-each select="$ordinary-members[position() >= $gap-start + $gap-size]">
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </xsl:if>

        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

应用于上述输入示例时,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <member id="4"/>
   <member id="2" place="2" start="1" size="1"/>
   <member id="5"/>
   <member id="6"/>
   <member id="3" place="5" start="2" size="2"/>
   <member id="7"/>
   <member id="8"/>
   <member id="9"/>
   <member id="1" place="9" start="4" size="3"/>
   <member id="10"/>
   <member id="11"/>
   <member id="12"/>
</output>

关于xml - 从两个 xml 文件在 XSLT 中排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24450926/

相关文章:

angularjs - 在基于 angularjs 构建的应用程序中查找元素的 xpath

xml - 如何使用属性值匹配两组节点而不使用两个 <xsl :for-each>

java - Eclipse 安卓配置问题

python - 如何在 python xml.etree.ElementTree 中删除迭代器内的节点

xml - xslt 将位置作为参数传递会产生奇怪的结果?

c# - 使用项目相对方式(而不是绝对路径)引用 XSLT 文件

xml - 使用 XSLT 用 href 属性包装所有元素

internet-explorer - 使用 XSLT 创建条件注释?

XSLT 函数 document() 使用通配符

xpath - 碎片 : Select tag with non-breaking space with xpath