Xpath 在选择嵌套在 <td 中的 <spans>时出现问题>

Xpath issues selecting <spans> nested in <td>

提问人:Lobstersack 提问时间:5/10/2020 更新时间:5/13/2020 访问量:511

问:

我正在尝试使用一个程序从许多 XHTML 文档中提取文本,该程序使用 Xpath 查询将文本映射到结构化表格中。XHTML 文档如下所示

<td class="td-3 c12" valign="top">
 <p class="pa-4">
  <span class="ca-5">text I would like to select </span>
 </p>
</td>
<td class="td-3 c13" valign="top">
 <p class="pa-2">
  <span class="ca-0">some more text I want to select </span>
 </p>
 <p class="pa-2">
  <span class="ca-0">
 <br>
 </br>
  </span>
 </p>
 <p class="pa-2">
 <span class="ca-5">text and values I don't want to select.</span>
 </p>
 <p class="pa-2">
  <span class="ca-5"> also text and values I don't want to </span>
 </p>
</td>

我能够按它们的类选择跨度并检索文本/值,但是它们不够唯一,我需要按表类进行过滤。例如,仅 SPAN 类 CA-0 中的文本是 TD 类 TD-3 C13 的子类

这将是<span class="ca-0">some more text I want to select </span>

我已经尝试了所有这些组合

//xhtml:td[@class="td-3 c13"]/xhtml:span[@class = "ca-0"]

//xhtml:span[@class = "ca-0"] //ancestor::xhtml:td[@class= "td-3 c13"]

//xhtml:td[@class="td-3 c6"]//xhtml:span[@class = "ca-0"]

HTML XML XPATH XHTML XQUERY

评论


答:

0赞 Jack Fleeting 5/10/2020 #1

我不确定您的示例 xml 在多大程度上反映了您的实际 xml,但严格基于您的示例 xml(并且忽略您可能会遇到的可能的命名空间问题),以下 xpath 表达式:

//td[contains(@class,"td-3")]/p[1]/span/text()

选择

text I would like to select
some more text I want to select

评论

0赞 Lobstersack 5/11/2020
尝试了几个变体,这是最接近的,我遇到了这个错误,当我尝试使用表类时,似乎很快就出现了,例如.class = “TD-3 c13” 它不起作用//xhtml:td[contains(@class,"td-3 c13")]/xhtm:p[1]/xhtm:span/text()XDMP-TOOFEWARGS: (err:XPST0017) fn:contains(@class = "td-3 c13") -- Too few args, expected 2 but got 1
0赞 Jack Fleeting 5/11/2020
@Lobstersack我不知道为什么Marklogic(我认为您正在使用的)会给您该错误消息。你所拥有的功能绝对是正确的。错误消息的格式无效:(请注意 而不是 )。我没有安装 ML,因此无法对其进行故障排除。也许这是一个错误?contains()contains(@class,"td-3 c13")containscontains(@class = "td-3 c13")=,
0赞 Lobstersack 5/12/2020
猜得好!这是标记逻辑。是的,可能是 MarkLogic Data Hub 的错误或您所说的命名空间问题。我尝试了 (@class = “td-3 c13”) 和 (@class, “td-3 c13”) 两种方式,并得到了两个不同的错误。我可以命中所有其他跨度类,但仍然无法将其缩小到表类。
0赞 Jack Fleeting 5/12/2020
@Lobstersack 使用时会遇到什么错误?(@class, "td-3 c13")
0赞 Lobstersack 5/12/2020
它通过而不会失败,但没有任何回报。似乎只对TD类这样做。感谢您到目前为止的所有帮助。
0赞 E.Wiest 5/11/2020 #2

根据文档,为了支持命名空间,您应该编写如下内容(fn:...):

//*:td[fn:contains(@class,"td-3")]/*:p[1]/*:span

或者使用绑定命名空间:

node.xpath("//xhtml:td[fn:contains(@class,'td-3')]/xhtml:p[1]/xhtml:span", {"xhtml":"http://example.com/ns"})

这个表达式也应该有效(选择每个 td 元素的第一个 p 的第一个跨度):

//*:td/*:p[1]/*:span[1]

旁注 :

您的 XPath 表达式可以修复。Span 不是子代,而是后代,所以我们使用 .我们习惯于只保留第一个结果。//()

(//xhtml:td[@class="td-3 c13"]//xhtml:span[@class = "ca-0"])[1]
(//xhtml:td[@class="td-3 c6"]//xhtml:span[@class = "ca-0"])[1]

替换为谓语://[]

(//xhtml:span[@class = "ca-0"][ancestor::xhtml:td[@class= "td-3 c13"]])[1]

使用以下命令测试您的 XPath: https://docs.marklogic.com/cts.validIndexPath

评论

0赞 Lobstersack 5/12/2020
谢谢你的回答。我仍然无法将其指向 td 类。我尝试了你给我看的所有例子,结果各不相同;第一个 ' -- arg1 不是 xs:string' 类型 第二个我无法运行。第三次奏效了!但是我仍然需要将其缩小到 td 类,例如 //*:td[@class = “td-3 c13”]/*:p[1]/*:span[1] - 这是有效的,但不返回任何内容。对于接下来的两个,我收到这个“arg1 不是 xs:string 类型”,这些 TD 类被诅咒了吗??哈哈。最后一个是有效的,什么也没产生。
0赞 Lobstersack 5/12/2020
好的,开始解决问题,我可以查询 //td[@class=“td-3”] 并获取所有 td-3 表,但是一旦添加 c13,例如 //td[@class=“td-3 c13”] 它就会返回空
0赞 E.Wiest 5/13/2020
如果它适用于 (返回 3 个元素),则它不适用于 . 只意味着一个解决方案,你已经找到了它。你不能更具体地介绍这个 td。你需要去别处看看。 还不够吗?请随时发布示例数据的更新版本。您使用哪个软件(+版本)?//td[@class="td-3"]//td[@class="td-3 c13"]@class=//*:td[@class = "td-3"]/*:p[1]/*:span[1]
0赞 Lobstersack 5/13/2020 #3

解决方案是//td[(@class ="td-3") and (@class = "c13)]/p/span

出于某种原因,它看到

<td class="td-3 c13">

作为单独的类,例如

<td class = "td-3" and class = "c13"

所以你需要这样对待它们

感谢 @E.Wiest 和 @JackFleeting 验证我并为我指明了正确的方向。