XSLT 2.0:查找序列中缺少的元素

时间:2012-03-11 18:56:18

标签: xslt-2.0 saxon xpath-2.0

我需要根据ID号搜索一系列元素。如果找到了ID号,我会处理它。如果找不到ID,则会使用默认值填写。我在Saxon 9.4 HE中使用XSLT 2.0。

这是一个非常简化的例子。输入XML如下所示:

<root>
    <item>
        <id>1</id>
    </item>
    <item>
        <id>2</id>
    </item>
    <item>
        <id>4</id>
    </item>
</root>

如果我正在搜索ID为1,2或3的项目,我想获得以下输出。请注意,我不希望第4项有任何输出。

Found 1
Found 2
Didn't find 3

我的第一次尝试是使用for-each循环,但它甚至没有编译。我得到的错误是“XPTY0020:Axis step child :: element('':id)不能在这里使用:上下文项是一个原子值”从行“”。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:variable name="ids" select="(1, 2, 3)"/>

<xsl:template match="/root">
    <xsl:for-each select="$ids">
        <xsl:choose>
            <xsl:when test="count(item/id = .) > 0">
                Found <xsl:value-of select="."/>
            </xsl:when>
            <xsl:otherwise>
                Didn't find <xsl:value-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template> 

</xsl:stylesheet>

之后我意识到我可以很容易地找到匹配的以下内容,但我无法找到找到遗漏的方法。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:variable name="ids" select="(1, 2, 3)"/>

<xsl:template match="/">
    <xsl:apply-templates select="root/item[id=$ids]"/>
</xsl:template> 

<xsl:template match="item">
    Found <xsl:value-of select="id"/>
</xsl:template> 

</xsl:stylesheet>
顺便说一句,输出也需要按ID排序,这意味着转储所有找到的项目的列表,然后列出未找到的项目列表将不起作用。这是否可能,或者我应该采取轻松/懦弱的道路并改变我的意见?

2 个答案:

答案 0 :(得分:1)

以下是一个例子:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:key name="k1" match="item" use="number(id)"/>

<xsl:param name="ids" select="(1, 2, 3)"/>

<xsl:template match="/">
    <xsl:variable name="root" select="."/>
    <xsl:for-each select="$ids">
      <xsl:choose>
        <xsl:when test="key('k1', ., $root)">
          <xsl:text>Found </xsl:text>
          <xsl:value-of select="."/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>Didn't find </xsl:text>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template> 

</xsl:stylesheet>

[编辑] 你的初始尝试是正确的,因为处理id序列是有关的,但你需要将主输入文档存储在for-each之外,因为在上下文项中是一个id号值而没有外部变量你不会能够访问文档中的项目元素。

为了提高效率,我添加了密钥。

答案 1 :(得分:1)

这是一个更简单(没有明确的条件)和更短的解决方案

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output method="text"/>

 <xsl:key name="kIdByVal" match="id" use="."/>

 <xsl:param name="psortedIds" as="xs:string+"
      select="'1','2','3'"/>

 <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="/*">
  <xsl:for-each select="$psortedIds">
   <xsl:sequence select=
   '("found ", "didn&apos;t find ")
       [2 - number(boolean(key("kIdByVal", current(), $vDoc)))],
    ., "&#xA;"
   '/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此XSLT 2.0转换

<root>
    <item>
        <id>1</id>
    </item>
    <item>
        <id>2</id>
    </item>
    <item>
        <id>4</id>
    </item>
</root>

产生了想要的正确结果

found  1 
 found  2 
 didn't find  3