根据一组其他元素中是否存在相同属性对选择进行排序

Make an ordering in a selection based on the presence of equal attribute in a set of other elements

我有这样的 XML 结构:

<people>
  <person id="1" name="Sam" />
  <person id="2" name="Dan" />
</people>
<executives>
  <executive id="1" name="Sam" favorite="yes" />
  <executive id="3" name="Ian" />
</executives>

我需要引用 people 中的所有节点,但我需要先浏览那些在 executives[=] 中有收藏夹 属性 的节点21=],然后剩下的。我想我需要以某种方式结合 <xsl:apply-templates select="/people/person[/executives/executive/@id = @id]" /><xsl:apply-templates select="/people/person[@favorite = 'yes']" />.

但是我不知道怎么办。

您可以通过使用键通过 name 属性

查找高管来简化事情
<xsl:key name="execs" match="executive" use="@name" />

然后,要得到高管喜欢的person个节点,可以这样使用key

<xsl:apply-templates select="person[key('execs', @name)/@favorite = 'yes']" />

你会否定获得其他人的条件。

假设您有一个格式良好的 XML(即具有根元素),试试这个 XSLT

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

    <xsl:key name="execs" match="executive" use="@name" />

    <xsl:template match="/">
        <people>
            <xsl:apply-templates select="//people" />
        </people>
    </xsl:template>

    <xsl:template match="people">
        <favorites>
            <xsl:apply-templates select="person[key('execs', @name)/@favorite = 'yes']" />
        </favorites>
        <other>
            <xsl:apply-templates select="person[not(key('execs', @name)/@favorite = 'yes')]" />
        </other>
    </xsl:template>

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

像下面这样的东西会起作用:

<!-- your root here, which you didn't show in the question -->
<xsl:template match="/root">
   <xsl:apply-templates select="people" />
</xsl:template>

<xsl:template match="people">
    <xsl:apply-templates select="person" mode="fav"/>
    <xsl:apply-templates select="person" mode="other"/>
</xsl:template>

<xsl:template match="person[@id = ../../executives/executive[@favorite = 'yes']/@id]" mode="fav">
    <favorite>
        <xsl:copy-of select="." />
    <favorite>
</xsl:template>

<!-- not a favorite -->
<xsl:template match="person" mode="fav" />

<!-- not a non-favorite -->
<xsl:template match="person" mode="other" />

<xsl:template match="person[not(@id = ../../executives/executive[@favorite = 'yes']/@id)]" mode="other">
    <non-favorite>
        <xsl:copy-of select="." />
    <non-favorite>
</xsl:template>

有更好的方法可以使用键来编写此代码(蒂姆同时给出了这样的解决方案),但我认为这就足够了,除非你有非常大的列表使得直接查找速度太慢。

我用于输出的结构应该根据您的需要进行调整。我使用了额外的元素来确保您收集到正确的元素。

这是另一种看待它的方式:

XSLT 1.0

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

<xsl:key name="x" match="executive" use="@id" />

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

<xsl:template match="people">
    <xsl:copy>
        <xsl:apply-templates select="person">
            <xsl:sort select="number(key('x', @id)/@favorite='yes')" data-type="number" order="descending"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

测试输入

<root>
    <people>
      <person id="1" name="Adam" />
      <person id="2" name="Betty" />
      <person id="4" name="David" />
      <person id="5" name="Eve" />
      <person id="6" name="Frank" />
      <person id="7" name="George" />
    </people>
    <executives>
      <executive id="3" name="Cecil" favorite="yes" />
      <executive id="5" name="Eve" />
      <executive id="6" name="Frank" favorite="yes" />
    </executives>
</root>

结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <people>
      <person id="6" name="Frank"/>
      <person id="1" name="Adam"/>
      <person id="2" name="Betty"/>
      <person id="4" name="David"/>
      <person id="5" name="Eve"/>
      <person id="7" name="George"/>
   </people>
   <executives>
      <executive id="3" name="Cecil" favorite="yes"/>
      <executive id="5" name="Eve"/>
      <executive id="6" name="Frank" favorite="yes"/>
   </executives>
</root>