2012-07-29 108 views
2

XML/XSL/Xpath的新手,我已经在这些板上搜索了一个看似简单的问题的答案,但也许我对XSL太陌生了,以便理解可能解决这个问题的一些答案。XSL问题:如何根据一组节点值选择一组节点?

我想选择一组搭配一组不同的文档存储在别处节点值的节点,使:

<body> 
    <partlist> 
     <part>head</part> 
     <part>spleen</part> 
     <part>toe</part> 
    </partlist> 
    <parts> 
     <head>this is a head</head> 
     <spleen>this is a spleen</spleen> 
     <toe>big toe</toe> 
     <toe>big toe</toe> 
    <parts> 
</body> 

所以,让我们说,我想指望所有的“零件” ,但我不知道“部分”节点名称,我想要一个XPath expr来匹配一组节点,其名称等于另一组节点的值...

我已经足够新XSL既想象一个解决方案非常简单,但经验丰富,足以认识到期望从XSL获得简单的解决方案是一个肯定的错误路径。

在我的基础程序,无知,这是我曾尝试:

<xsl:template match="/"> 
    <xsl:apply-templates select="partlist/part"> 
     <xsl:with-param name="parts" select="parts"/> 
    </xsl:apply-templates> 
</xsl:template> 
<xsl:template match="part"> 
    <xsl:param name="parts"/> 
    <xsl:value-of select="count($parts[.])"/>   
</xsl:template> 

但是,这是完全错误的。任何帮助深表感谢。

编辑:谢谢你的答案,但我认为我没有被理解 - 错误是我的,因为我还没有完全清楚......我需要的是一个单一的结果告诉我,如果有任何与引用集的节点值相匹配的节点...我认为会更改查询,因为我没有尝试输出计数列表,我试图将集合与集合进行匹配以计算总数。 。但让我XSL澄清,如果这样的事情是可能的。这里是我上面的代码稍加修改,使我的意图明显:

<xsl:template match="/"> 
    <xsl:apply-templates select="partlist/part"> 
     <xsl:with-param name="parts" select="parts"/> 
    </xsl:apply-templates> 
</xsl:template> 
<xsl:template match="part"> 
    <xsl:param name="parts"/> 
    <xsl:if select="count($parts[.]) &gt; 0">1</xsl:if>   
</xsl:template> 
当应用到XML文档例子

上述应该输出:

1 

这是否有意义?

编辑:我还应该指定,我仅限于XSL 1.0

+0

我有不祥的预感,这个问题将是其中的一个“如果你了解XSL和XPath,你就不会问这样的问题”,这基本上意味着它不能做完了。我得说,在程序和oop背景下,我很困惑,为什么有人会设计一种语言,答案是如此频繁,“不能这样做”。 – user1558945 2012-07-30 06:46:49

+1

对于XSLT,我从来没有听说过“它不能完成”。在某些情况下,这肯定不太明显,但始终可以完成。 XSLT具有功能性背景,这就是为什么OOP /命令式背景的人看起来很奇怪。与过程相比,XSLT解决方案非常容易*的情况也很多*。几乎所有涉及[身份模板](http://www.xmlplease.com/xsltidentity) – 2012-07-30 14:48:31

回答

1

可以使用local-name()函数来获取一个节点的名称,以便您可以针对给定的值进行比较。

例如,样式表可以修改此:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/"> 
    <xsl:apply-templates select="body/partlist/part"/> 
    </xsl:template> 

    <xsl:template match="part"> 
    <xsl:variable name="part" select="."/> 
    <xsl:value-of select="count(/body/parts/*[local-name() = $part])"/> 
    </xsl:template> 

</xsl:stylesheet> 

编辑补充:

您也可以比较值的集合,而不只是单一的值。从XPath 1.0 spec, section 3.4

如果一个要比较的对象是一个节点集合,而另一个是一个字符串, 则比较为真,当且仅当存在中的一个节点的 节点集合,使得对节点的 字符串值和另一个字符串执行比较的结果为true。

如果要算你有多少元素具有/body/parts其本地名称下/body/partlist/part列出的部分相匹配,你可以用这个XPath表达式做到这一点:

count(/body/parts/*[local-name() = /body/partlist/part]) 

从问题中的最后一个转型,添加了编辑之后,可以改写,例如像这样:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="body"> 
    <xsl:apply-templates select="partlist"> 
     <xsl:with-param name="parts" select="parts"/> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="partlist"> 
    <xsl:param name="parts"/> 
    <xsl:if test="count($parts/*[local-name() = current()/part]) &gt; 0">1</xsl:if>   
    </xsl:template> 

</xsl:stylesheet> 
+0

谢谢,这很明显,不幸的是我看到我的答案不是。我已经修改了它,所以希望它更有意义:它不是我想比较的单个值,它是一组值... – user1558945 2012-07-29 23:08:35

+0

@ user1558945,编辑了如何与一组值而不只是一个 – 2012-07-30 14:13:49

+0

辉煌,谢谢!我正要放弃。 – user1558945 2012-07-30 15:44:22

1

一本XSLT 1.0转换

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

<xsl:template match="part"> 
    <xsl:value-of select="."/> 

    <xsl:value-of select= 
    "concat(': ', 
      count(/*/parts/*[name() = current()]), 
      '&#xA;')"/> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

当所提供的XML文档应用:

<body> 
    <partlist> 
     <part>head</part> 
     <part>spleen</part> 
     <part>toe</part> 
    </partlist> 
    <parts> 
     <head>this is a head</head> 
     <spleen>this is a spleen</spleen> 
     <toe>big toe</toe> 
     <toe>big toe</toe> 
    </parts> 
</body> 

产生想要的,正确的结果

head: 1 
spleen: 1 
toe: 2 

说明

正确使用模板和current()函数。


二,与单个的XPath 2.0表达式:

/*/partlist 
     /part 
      /concat(., 
        ': ', for $p in . 
         return count(/*/parts/*[name() eq $p]), 
        '&#xA;' 
       ) 

当此XPath 2.0表达式与相同的XML文档(上图),有用的,正确的结果产生评价:

head: 1 
spleen: 1 
toe: 2 

这里是基于XSLT 2.0的验证

<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:template match="/"> 
    <xsl:sequence select= 
    "/*/partlist 
     /part 
      /concat(., 
        ': ', for $p in . 
         return count(/*/parts/*[name() eq $p]), 
        '&#xA;' 
       ) 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

更新

的OP已经改变的问题,似乎他想:

我需要的是一个单一的结果告诉我,如果有 匹配的节点值的任何节点

0123: - 转诊集...

这同样简单的事情可以用一个XPath表达式获得

该表达式评估为true()准确时,有一些/*/parts/*name()/*/partlist/part元素的字符串值中的一个。

上述表达式可以用“原样”在其中一个布尔期望(例如在任何谓词任何地方,作为xsl:ifxsl:when指令的test属性的值,...,等等。

如果该值为1而被通缉(ANF不true()),只需使用:

number(/*/parts/*[name() = /*/partlist/part]) 

这给了我们想要的结果1或0,因为根据定义:

number(true()) = 1 

number(false()) = 0