Bash功能本身不太适合解析XML。
此著名的Bash FAQ指出:
请勿不要使用sed,awk,grep等尝试 [从XML文件中提取数据] 上(它指向undesired results)。
考虑利用XML特定的命令行工具,例如XMLStarlet。如果尚未安装XML Starlet,请参阅下载信息here。
解决方案:
使用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
的前缀。 / li>
-
-d
-删除匹配的节点。
-
'//x:entry[not(child::x:link[@href="https://myhomesite.com"])]'
xpath表达式用于查找/匹配问题中指定的适当节点。
所有链接(/ feed / entry)所在的链接href!= http://myhomesite.com
。
如您所见,在XPath表达式中,我们在元素节点名称之前添加x
前缀,即x:entry
和x:link
,以确保我们在正确的命名空间中寻址元素。
-
/path/to/file.rss
-源.rss
文件的路径名。
保存生成的XML(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
-
或者,利用redirection operator(>
)并指定保存输出的位置的路径名。例如,以下复合命令会将结果保存到新文件中:
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()
的XPath:
鉴于您的示例源XML(RSS)不包含任何QNames,因此还可以利用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
选项将名称空间绑定到前缀。有关此功能的更多信息,请参考XMLStarlet文档中标题为1.3. A More Convenient Solution的部分。
例如:
xml ed -d '//_:entry[not(child::_:link[@href="https://myhomesite.com"])]' /path/to/file.rss
要进一步了解当源XML使用名称空间时如何使用XMLStarlet,我建议您还阅读文档中的Namespaces and default namespace。
编辑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
本文链接:https://www.f2er.com/3161649.html