如何表达 XPath 函数来输出每个输入元素?

如何表达 XPath 函数来输出每个输入元素?

我正在使用这个命令:

xmllint --xpath 'substring-after(string(//item/link), "_")' rss.xml

并获得所需的输出,但它位于第一个元素上。我将如何解决这个问题以将其应用于每个link

我愿意使用任何实用程序,只要接受示例输入并且可以使用一个表达式来获得所需的输出。

输入示例:

<rss version="2.0">
  <channel>
    <title>Malicious IPs | By Last Bad Event | Project Honey Pot</title>
    <link><![CDATA[http://www.projecthoneypot.org/list_of_ips.php]]></link>
    <description/>
    <copyright>Copyright 2021 Unspam Technologies, Inc</copyright>
    <language>en-us</language>
    <lastBuildDate>July 03 2021 07:15:12 PM</lastBuildDate>
    <image>
      <url>http://www.projecthoneypot.org/images/small_phpot_logo.jpg</url>
      <title>Project Honey Pot | Distribute Spammer Tracking System</title>
      <link>http://www.projecthoneypot.org</link>
    </image>
    <item>
      <title>92.204.241.167 | C</title>
      <link>http://www.projecthoneypot.org/ip_92.204.241.167</link>
      <description>Event: Bad Event | Total: 3,061 | First: 2021-03-27 |  Last: 2021-07-03</description>
      <pubDate>July 03 2021 07:15:12 PM</pubDate>
    </item>
    <item>
      <title>181.24.239.244</title>
      <link>http://www.projecthoneypot.org/ip_181.24.239.244</link>
      <description>Event: Bad Event | Total: 1 | First: 2021-07-03 |  Last: 2021-07-03</description>
      <pubDate>July 03 2021 07:15:12 PM</pubDate>
    </item>
    <item>
      <title>193.243.195.66 | S</title>
      <link>http://www.projecthoneypot.org/ip_193.243.195.66</link>
      <description>Event: Bad Event | Total: 4 | First: 2021-06-12 |  Last: 2021-07-03</description>
      <pubDate>July 03 2021 07:15:12 PM</pubDate>
    </item>
  </channel>
</rss>

期望的输出:

92.204.241.167
181.24.239.244
193.243.195.66

当前输出:

92.204.241.167

答案1

使用xmlstarlet

xmlstarlet sel -t -m '//item/link' -v 'substring-after(., "_")' -nl rss.xml

这首先匹配 ( -m) 所有//item/link节点,然后获取-v与匹配节点值中第一个下划线字符后面的字符串关联的值 ( )。最终-nl在每个结果字符串之间输出一个换行符。

substring-after()将为集合中与第一个表达式匹配的每个节点计算第二个表达式 ( )。

答案2

实际上仅使用 XPath 1.0 无法实现这一目标。您无法返回字符串序列,因为 XPath 1.0 中没有此类数据类型,并且您无法返回连接各个子字符串的单个字符串,因为您仍然需要子字符串序列作为中间结果,并且同样,不存在这样的数据类型。因此,您要么需要迁移到 XPath 2.0+,要么需要执行多个 XPath 表达式的主机语言的一些帮助 - 这就是 @Kusalananda 的 xmlstarlet 解决方案正在做的事情。

然而,您使用的是命令行,因此有非常广泛的可用工具可供选择 - 您可以像使用 XPath 一样轻松地使用 XQuery,而且您当然不会局限于古老的 XPath 1.0 版本。例如,对于撒克逊人,你可以这样做

java net.sf.saxon.Query -qs:"//item/link!substring-after(., '_')" -s:rss.xml

这使用 XPath 3.0 和 XQuery 3.0 中可用的“bang”运算符,它将右侧的表达式应用于左侧表达式选择的每个项目。

答案3

我的希德尔是另一个运行现代 XPath 表达式的工具:

xidel rss.xml --xpath "//item/link/substring-after(., '_')"

相关内容