我有 RSS 提要,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>my feed</title>
<link rel="self" href="http://myhomesite.com/articles/feed/"/>
<updated>2019-11-04T12:45:00Z</updated>
<id>http://myhomesite.com/articles/feed/?dt=2019-11-04T12:45:00Z</id>
<entry>
<id>id0</id>
<link rel="alternate" type="text/html" href="https://yandex.ru/link123"/>
<author>
<name/>
</author>
<published>2019-11-04T12:45:00Z</published>
<updated>2019-11-04T12:45:00Z</updated>
<title type="html"><![CDATA[foo bar foo bar]]></title>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<id>id2</id>
<link rel="alternate" type="text/html" href="https://myhomesite.com"/>
<author>
<name/>
</author>
<published>2019-11-04T09:45:00Z</published>
<updated>2019-11-04T09:45:00Z</updated>
<title type="html"><![CDATA[foo bar foo bar]]></title>
<content type="html"><![CDATA[]]></content>
</entry>
....
我想删除链接href != 的所有节点 ( /feed/entry
) 。 http://myhomesite.com
如何使用 Bash 删除值从指定符号开始的 XML 节点?
Bash 特性本身并不是很适合解析 XML。
这个著名的Bash 常见问题说明如下:
考虑使用特定于 XML 的命令行工具,例如XMLStarlet。如果您尚未安装 XML Starlet,请在此处查看下载信息。
使用 XML Starlet,您可以运行以下命令将所需的结果输出到您的终端:
xml ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss
注意:/path/to/file.rss
上面显示的命令末尾的部分应替换为实际.rss
文件的真实路径名。
解释:
上述命令的部分分解如下:
xml
- 调用 XML Starlet 命令。
ed
- 编辑/更新 XML 文档。
-N x="http://www.w3.org/2005/Atom"
- 该-N
选项将命名空间,即http://www.w3.org/2005/Atom
,绑定到我们任意命名的前缀x
。
-d
- 删除匹配的节点。
'//x:entry[not(child::x:link[@href="https://myhomesite.com"])]'
用于查找/匹配问题中指定的适当节点的xpath表达式。
链接 href != 的所有节点(/feed/entry)
http://myhomesite.com
。
正如你所看到的,在XPath表达式我们前面加上x
前缀元素节点名称,即x:entry
和x:link
,以确保我们解决了正确的命名空间中的元素。
/path/to/file.rss
- 源.rss
文件的路径名。
要保存结果 XML,您可以:
将--inplace
选项添加到上述命令 - 这将.rss
用所需的结果覆盖原始命令。例如:
xml ed --inplace -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss
或者,使用重定向运算符( >
) 并指定保存输出位置的路径名。例如,以下复合命令会将结果保存到新文件中:
xml ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss > /path/to/results.rss
注:在/path/to/results.rss
在上述复合命令的,应该用真实的路径到要保存新文件取代。
local-name()
:鉴于您的示例源 XML (RSS) 不包含任何QName,因此也可以利用 XPath 的local-name()
功能。这将不需要使用 XMLStarlet 的-N
选项绑定命名空间。例如:
xml ed -d '//*[local-name() = "entry" and not(child::*[local-name() = "link"][@href="https://myhomesite.com"])]' /path/to/file.rss
重要提示:您可能需要将本文xml
中显示的所有示例命令中的前导部分xmlstarlet
替换为。例如:
xmlstarlet ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss.
^^^^^^^^^^
编辑:
鉴于你的示例XML它也可以利用默认的命名空间,这是使用简化的语法_:
来代替x:
。通过使用下划线 ( _
),您无需使用该-N
选项将命名空间绑定到前缀。请参阅标题为1.3的部分。有关此功能的更多信息,请参阅 XMLStarlet 文档中的更方便的解决方案。
例如:
xml ed -d '//_:entry[not(child::_:link[@href="https://myhomesite.com"])]' /path/to/file.rss
为了在源 XML 使用命名空间时进一步了解使用 XMLStarlet,我建议还阅读文档中的命名空间和默认命名空间。
编辑2:
OP 的作者随后在评论中写道:
多一问。条件
[not(child::_:link[@href="myhomesite.com"])]
很严格。我想成为类似开始myhomesite.com
但 URI 不重要的东西,即myhomesite.com**anything**
. 这是可能的?[原文]像这样的东西..
xmlstarlet ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[matches(@href, '^https://myhomesite.com/' )]/@href)]' feed.rs
考虑将 Xpath 的starts-with()
函数与前面给出的任何一个示例结合使用。例如:
使用-N
选项和starts-with()
:
xml ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[starts-with(@href, "https://myhomesite.com")])]' file.rss
使用local-name()
和starts-with()
:
xml ed -d '//*[local-name() = "entry" and not(child::*[local-name() = "link"][starts-with(@href, "https://myhomesite.com")])]' file.rss
使用默认命名空间的简化语法,即下划线,以及starts-with()
:
xml ed -d '//_:entry[not(child::_:link[starts-with(@href, "https://myhomesite.com")])]' file.rss
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句