Xslt 重新排序从xsl返回的节点:choose

Xslt 重新排序从xsl返回的节点:choose,xslt,xslt-1.0,remap,xsl-choose,Xslt,Xslt 1.0,Remap,Xsl Choose,使用xsl:choose(XSLT 1.0)重新排列所选节点组的有效方法是什么 以下是示例源XML: <Universe> <CObj> <Galaxies> <Galaxy> <Profile> <Name>MilkyWay</Name> <Age>12.5</Age>

使用xsl:choose(XSLT 1.0)重新排列所选节点组的有效方法是什么

以下是示例源XML:

<Universe>
 <CObj>
    <Galaxies>
        <Galaxy>
            <Profile>
                <Name>MilkyWay</Name>
                <Age>12.5</Age>
            </Profile>
            <PlanetarySystem>
                <Name>Solar</Name>
                <Location></Location>
                <Planet>
                    <Name>Earth</Name>
                    <Satellite>Y</Satellite>
                              ...
                              ...
                              ...
                </Planet>
                        ...
                        ...
                        ...
            </PlanetarySystem>
            <PlanetarySystem>
                        ...
                        ...
                        ...
            </PlanetarySystem>
        </Galaxy>
        <Galaxy>
                ...
                ...
                ...
        </Galaxy>
    </Galaxies>
 </CObj>
</Universe>

银河系
12.5
太阳的
土
Y
...
...
...
...
...
...
...
...
...
...
...
...
XSL代码段:

<xsl:template name="get-galaxy-types">
<xsl:variable name="galaxy_age1" select ="1"  />
<xsl:variable name="galaxy_age2" select ="5"  />
<xsl:variable name="galaxy_age3" select ="10"  />
<xsl:for-each select="Galaxies/Galaxy/Profile/Age">
        <xsl:choose>
            <xsl:when test=".=$galaxy_age2">
                <GalaxyType2>
                    <xsl:value-of select="../Profile/Name"/>
                </GalaxyType2>
            </xsl:when>
            <xsl:when test=".=$galaxy_age3">
                <GalaxyType3>
                    <xsl:value-of select="../Profile/Name"/>
                </GalaxyType3>
            </xsl:when>
            <xsl:when test=".=$galaxy_age1">
                <GalaxyType1>
                    <xsl:value-of select="../Profile/Name"/>
                </GalaxyType1>
            </xsl:when>
        </xsl:choose>
</xsl:for-each>

从主模板调用上述XSL模板,如:

<xsl:template match="Universe">
    <GalaxyTypes>
        <xsl:call-template name="get-galaxy-types"/>
    </GalaxyTypes>
</xsl:template>

输出XML: 请注意,
的顺序不能更改

<Universe>
...
...
...
  <GalaxyTypes>
      <GalaxyType2>xxxxxx</GalaxyType2>
      <GalaxyType3>xxxxxx</GalaxyType3>
      <GalaxyType1>xxxxxx</GalaxyType1>
  </GalaxyTypes>
...
...
...
</Universe>

...
...
...
xxxxxx
xxxxxx
xxxxxx
...
...
...
由于
xsl:choose
在找到匹配项时返回XML节点,因此我无法找到一种直接的方法来控制
GalaxyType
在输出XML中的显示顺序


我如何拥有一个通用模板来对将来可能添加的、可能符合类似要求的任何元素执行重新排序。我可以在这个XSL中使用一个重新映射模板,但我不确定如何以一种非常优雅和高效的方式实现这一点。

在分散的代码片段之间导航非常困难。不过,在我看来,你应该改变你的战略,比如:

<xsl:template match="?">
...
    <GalaxyTypes>
        <xsl:apply-templates select="??/???/Galaxy">
            <xsl:sort select="Profile/Age" data-type="number" order="ascending"/>
        </xsl:apply-templates=>
     </GalaxyTypes>
...
</xsl:template>


<xsl:template match="Galaxy">
       <xsl:choose>
            <xsl:when test="Profile/Age=$galaxy_age1">
                <GalaxyType1>
                    <xsl:value-of select="Profile/Name"/>
                </GalaxyType1>
            </xsl:when>
            <xsl:when test="Profile/Age=$galaxy_age2">
                <GalaxyType2>
                    <xsl:value-of select="Profile/Name"/>
                </GalaxyType2>
            </xsl:when>
            <xsl:when test="Profile/Age=$galaxy_age3">
                <GalaxyType3>
                    <xsl:value-of select="Profile/Name"/>
                </GalaxyType3>
            </xsl:when>
        </xsl:choose>
</xsl:template>

...
...
--

请注意,如果所有星系都是一个统一的
元素,并使用类型属性来区分它们,则输出的格式会更好。

我猜您希望首先放置匹配星系-age1的星系,然后放置匹配星系-age2的星系,最后是galaxy-age3的版本。我还假设指定的年龄可能不是按升序排列的(也就是说,galaxy-age3可能小于galaxy-age1

首先,对Galaxy元素执行xsl:for-each可能更自然

<xsl:for-each select="Galaxies/Galaxy">
但这并不是很优雅。最好是简单地使用一个匹配Galaxy
的模板,并使用三个单独的xsl:apply templates来选择Galaxy;每个年龄一个

也试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />

<xsl:param name="galaxy_age1" select="1" />
<xsl:param name="galaxy_age2" select="5" />
<xsl:param name="galaxy_age3" select="10" />

<xsl:template match="Universe">
    <GalaxyTypes>
        <xsl:apply-templates select="Galaxies/Galaxy[Profile/Age = $galaxy_age1]">
            <xsl:with-param name="num" select="1" />
        </xsl:apply-templates>
        <xsl:apply-templates select="Galaxies/Galaxy[Profile/Age = $galaxy_age2]">
            <xsl:with-param name="num" select="2" />
        </xsl:apply-templates>
        <xsl:apply-templates select="Galaxies/Galaxy[Profile/Age = $galaxy_age3]">
            <xsl:with-param name="num" select="3" />
        </xsl:apply-templates>
    </GalaxyTypes>
</xsl:template>

<xsl:template match="Galaxy">
    <xsl:param name="num" />
    <xsl:element name="Galaxy{$num}">
        <xsl:value-of select="Profile/Name"/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />

<xsl:param name="galaxy_age1" select="1" />
<xsl:param name="galaxy_age2" select="10" />
<xsl:param name="galaxy_age3" select="5" />

<xsl:key name="galaxy" match="Galaxy" use="Profile/Age" />

<xsl:template match="Universe">
    <GalaxyTypes>
        <xsl:apply-templates select="key('galaxy', $galaxy_age1)">
            <xsl:with-param name="num" select="1" />
        </xsl:apply-templates>
        <xsl:apply-templates select="key('galaxy', $galaxy_age2)">
            <xsl:with-param name="num" select="2" />
        </xsl:apply-templates>
        <xsl:apply-templates select="key('galaxy', $galaxy_age3)">
            <xsl:with-param name="num" select="3" />
        </xsl:apply-templates>
    </GalaxyTypes>
</xsl:template>

<xsl:template match="Galaxy">
    <xsl:param name="num" />
    <xsl:element name="Galaxy{$num}">
        <xsl:value-of select="Profile/Name"/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

<> > > >编辑:,为了使这更有效,请考虑使用一个关键字来查找<强> Galaxy>元素。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />

<xsl:param name="galaxy_age1" select="1" />
<xsl:param name="galaxy_age2" select="5" />
<xsl:param name="galaxy_age3" select="10" />

<xsl:template match="Universe">
    <GalaxyTypes>
        <xsl:apply-templates select="Galaxies/Galaxy[Profile/Age = $galaxy_age1]">
            <xsl:with-param name="num" select="1" />
        </xsl:apply-templates>
        <xsl:apply-templates select="Galaxies/Galaxy[Profile/Age = $galaxy_age2]">
            <xsl:with-param name="num" select="2" />
        </xsl:apply-templates>
        <xsl:apply-templates select="Galaxies/Galaxy[Profile/Age = $galaxy_age3]">
            <xsl:with-param name="num" select="3" />
        </xsl:apply-templates>
    </GalaxyTypes>
</xsl:template>

<xsl:template match="Galaxy">
    <xsl:param name="num" />
    <xsl:element name="Galaxy{$num}">
        <xsl:value-of select="Profile/Name"/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />

<xsl:param name="galaxy_age1" select="1" />
<xsl:param name="galaxy_age2" select="10" />
<xsl:param name="galaxy_age3" select="5" />

<xsl:key name="galaxy" match="Galaxy" use="Profile/Age" />

<xsl:template match="Universe">
    <GalaxyTypes>
        <xsl:apply-templates select="key('galaxy', $galaxy_age1)">
            <xsl:with-param name="num" select="1" />
        </xsl:apply-templates>
        <xsl:apply-templates select="key('galaxy', $galaxy_age2)">
            <xsl:with-param name="num" select="2" />
        </xsl:apply-templates>
        <xsl:apply-templates select="key('galaxy', $galaxy_age3)">
            <xsl:with-param name="num" select="3" />
        </xsl:apply-templates>
    </GalaxyTypes>
</xsl:template>

<xsl:template match="Galaxy">
    <xsl:param name="num" />
    <xsl:element name="Galaxy{$num}">
        <xsl:value-of select="Profile/Name"/>
    </xsl:element>
</xsl:template>
</xsl:stylesheet>


这个顺序是不是会以升序的方式
GalaxyType
呢?最终输出的顺序需要与上面提到的不同,并且可能会根据用户的需求而变化。这就是我考虑是否可以从调用的模板
获取galaxy Type
重新映射XML节点的原因。此外,我无法更改源/输出XML。@Thinkster我的印象是年龄类型取决于年龄并按顺序排列。如果不是这样,您需要澄清这些类型是如何传递到样式表的。它们是否总是正好有三个(从您的硬编码中可以看出)是的,GalaxyTypes与年龄有关,但根据消费者的需要按自定义顺序进行排序。年龄值在
xsl:variable
中传递(有更新的问题)。这些变量是为测试而硬编码的,但这是在调用XSL编译器时从代码中设置的。计数不会动态更改,并且在设置后将保持不变。我仍然感到困惑:是什么决定了顺序?是不是在样式表中显示的变量的顺序?您的示例在这方面是矛盾的。--我也不是确定您认为如何“在调用XSL编译器时从代码中”传递变量。我相信您需要使用参数来实现这一点?是的,这些是作为参数传递的。我开始研究它,假设
XSL:choose
将保持返回节点的顺序,因此我按照该顺序进行了
XSL:when
比较(sry这不是我最初想要的顺序,我只是修改了XSL片段)。由于这不起作用,因为从
xsl:choose
返回的节点集顺序取决于首先匹配的内容,因此我正在寻找一种方法来定义自定义顺序,其中从
xsl:choose
重新运行的节点集将被重新排序。是的,这会起作用,但这会比
xsl:choose
更有效吗?因为如果我没有错,这将迭代多少次,最多3次(或更多,取决于计数),在使用
xsl:choose
时,我们可以通过一次运行匹配所有内容?这就是我认为如果我可以运行一次并重新映射返回的节点集的原因