Bash - 如果子节点的属性值不等于特定值,则删除 XML 节点?

安东·舍夫佐夫

我有 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 文件中提取数据]使用等(这会导致不希望的结果)。

考虑使用特定于 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"])]'用于查找/匹配问题中指定的适当节点表达式。

    链接 href != 的所有节点(/feed/entry)http://myhomesite.com

    正如你所看到的,在XPath表达式我们前面加上x前缀元素节点名称,即x:entryx:link,以确保我们解决了正确的命名空间中的元素。

  • /path/to/file.rss- 源.rss文件的路径名

保存结果 XML (RSS)

要保存结果 XML,您可以:

  1. --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
    
  2. 或者,使用重定向运算符( >) 并指定保存输出位置的路径名。例如,以下复合命令会将结果保存到新文件中:

     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在上述复合命令的,应该用真实的路径到要保存新文件取代。

XPath 与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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如果子节点等于数组值,则删除 XML 节点

来自分类Dev

如果属性具有特定值,则删除XML节点

来自分类Dev

检索XML节点结构-Bash

来自分类Dev

如果子节点包含特定字符串,则删除 xml 中的父节点

来自分类Dev

PowerShell:如果子节点符合特定条件,则删除xml节点

来自分类Dev

如果子节点包含特定字符串,则删除XML节点

来自分类Dev

JAVA 根据属性值删除 XML 节点

来自分类Dev

基于 Python 中的属性值从 XML 节点中删除节点

来自分类Dev

获取特定节点的xml属性值

来自分类Dev

解析XML以获取bash脚本中的节点值?

来自分类Dev

Bash将子节点插入XML文件

来自分类Dev

从 XML 中删除完整节点,如果子属性不包含特定文本 `WorkFlow/@name != 'UNS_SMTP_SERVICES'`

来自分类Dev

返回 XML 节点值

来自分类Dev

从XML获取节点值

来自分类Dev

从xml检索节点值

来自分类Dev

如果子节点具有特定属性,则删除父节点

来自分类Dev

如果子节点没有值,则删除父节点

来自分类Dev

基于节点属性值的Echo XML子节点值

来自分类Dev

节点值内的Java XML节点

来自分类Dev

根据节点值使用xslt从xml中删除节点

来自分类Dev

在Xml中删除节点值而不是整个节点

来自分类Dev

用子节点的值替换 XML 父节点的属性

来自分类Dev

ASP XML 按特定节点值选择节点?

来自分类Dev

XPath选择没有特定值的子节点的XML节点?

来自分类Dev

删除xml文件中具有特定值的子节点

来自分类Dev

Xml按元素值删除节点

来自分类Dev

删除特定的xml节点Javascript

来自分类Dev

从xml中删除特定节点

来自分类Dev

php中xml的每个节点属性值