选择包含特定子字符串的所有节点的XSLT

5

我正在尝试编写一个XPath,用于选择包含特定单词的某些节点。在这种情况下,单词是“Lockwood”。正确答案是3。这两个路径都给了我3。

count(//*[contains(./*,'Lockwood')])
count(BusinessLetter/*[contains(../*,'Lockwood')])

但是当我尝试输出每个特定节点的文本时
//*[contains(./*,'Lockwood')][1]
//*[contains(./*,'Lockwood')][2]
//*[contains(./*,'Lockwood')][3]

节点1最终包含了所有的文本,而节点2和3是空的。

请问有人能告诉我发生了什么或者我做错了什么吗。

谢谢。

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="XPathFunctions.xsl"?>
<BusinessLetter>
 <Head>
  <SendDate>November 29, 2005</SendDate>
  <Recipient>
   <Name Title="Mr.">
    <FirstName>Joshua</FirstName>
    <LastName>Lockwood</LastName>
   </Name>
   <Company>Lockwood &amp; Lockwood</Company>
   <Address>
    <Street>291 Broadway Ave.</Street>
    <City>New York</City>
    <State>NY</State>
    <Zip>10007</Zip>
    <Country>United States</Country>
   </Address>
  </Recipient>
 </Head>
 <Body>
  <List>
   <Heading>Along with this letter, I have enclosed the following items:</Heading>
   <ListItem>two original, execution copies of the Webucator Master Services Agreement</ListItem>
   <ListItem>two original, execution copies of the Webucator Premier Support for Developers Services Description between Lockwood &amp; Lockwood and Webucator, Inc.</ListItem>
  </List>
  <Para>Please sign and return all four original, execution copies to me at your earliest convenience.  Upon receipt of the executed copies, we will immediately return a fully executed, original copy of both agreements to you.</Para>
  <Para>Please send all four original, execution copies to my attention as follows:

 <Person>
    <Name>
     <FirstName>Bill</FirstName>
     <LastName>Smith</LastName>
    </Name>
    <Address>
     <Company>Webucator, Inc.</Company>
     <Street>4933 Jamesville Rd.</Street>
     <City>Jamesville</City>
     <State>NY</State>
     <Zip>13078</Zip>
     <Country>USA</Country>
    </Address>
   </Person>
  </Para>
  <Para>If you have any questions, feel free to call me at <Phone>800-555-1000 x123</Phone> or e-mail me at <Email>bsmith@webucator.com</Email>.</Para>
 </Body>
 <Foot>
  <Closing>
   <Name>
    <FirstName>Bill</FirstName>
    <LastName>Smith</LastName>
   </Name>
   <JobTitle>VP of Operations</JobTitle>
  </Closing>
 </Foot>
</BusinessLetter>

好问题,加一。请看我的答案,有解释、完整而简单的解决方案,并有一个有用的规则可以记住。 :) - Dimitre Novatchev
1个回答

11
但是当我尝试输出每个特定节点的文本时
//*[contains(./*,'Lockwood')][1] 
//*[contains(./*,'Lockwood')][2] 
//*[contains(./*,'Lockwood')][3] 

第一个节点包含了所有文本,而第二个和第三个节点为空。

这是常见问题解答。

//SomeExpression[1]

不等同于

(//someExpression)[1]

前者选择所有父元素的第一个子节点,该子节点是//SomeExpression节点。

后者选择整个文档中第一个(按文档顺序)的//SomeExpression节点。

这如何应用于您的问题?

//*[contains(./*,'Lockwood')][1]

这个选择器会选取所有至少有一个子元素其字符串值包含“Lockwood”的元素,并且它们是其父元素的第一个这样的子元素。所有包含字符串“Lockwood”的文本节点是其父元素的第一个这样的子元素,因此结果是选中了三个元素。

//*[contains(./*,'Lockwood')][2]

没有元素具有包含字符串“Lockwood”的子元素,并且是其父元素的第二个这样的子元素。没有节点被选中。

//*[contains(./*,'Lockwood')][3]

没有任何元素的子元素包含字符串"Lockwood"且是其父元素的第三个子元素。没有节点被选中。

解决方案:

使用:

(//*[contains(./*,'Lockwood')])[1]
(//*[contains(./*,'Lockwood')])[2]
(//*[contains(./*,'Lockwood')])[3]
每个选择器都精确地选取了由//*[contains(./*,'Lockwood')]选择的第N个元素(其中N = {1,2,3}),分别是:BusinessLetterRecipientBody
请记住:中括号[]运算符的优先级高于双斜杠//缩写。

1
+1 好答案。来自 http://www.w3.org/TR/xpath/#NT-Predicate 的正式定义:谓语根据轴过滤节点集以生成新的节点集。而 //*[1] 会被扩展为 /descendant-or-self::node()/child::*[1] - user357812

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接