【问题标题】:Search Keys and Replace Values in XML在 XML 中搜索键和替换值
【发布时间】:2017-02-03 15:39:57
【问题描述】:

我有一个如下所示的 xml 文件

<name>abcdefg</name>
<value>123456</value>

我正在尝试使用 sed 编写脚本来搜索标签“abcdefg”,然后替换相应的值“123456”,但不幸的是我无法找到实现上述逻辑的逻辑。 需要帮助!

【问题讨论】:

  • beautifulSoup 是从 html 读取标签的好方法。
  • 你的结构是什么样的?是&lt;item&gt;&lt;key&gt;k1&lt;/key&gt;&lt;value&gt;v1&lt;/value&gt;&lt;item&gt;&lt;key&gt;k2&lt;/key&gt;&lt;value&gt;v2&lt;/value&gt;&lt;/item&gt;吗?还是&lt;items&gt;&lt;key&gt;k1&lt;/key&gt;&lt;value&gt;v1&lt;/value&gt;&lt;key&gt;k2&lt;/key&gt;&lt;value&gt;v2&lt;/value&gt;&lt;/items&gt;?如果我们不知道结构,我们就无法提供语义感知的答案。
  • ...并且,明确地说,不是语义感知的答案必然是错误的:它将无法区分 cmets 和 CDATA部分和文字内容。

标签: python xml shell replace sed


【解决方案1】:

使用可识别 XML 的工具。这将使您的方法更加健壮:这意味着文本描述中的微小更改(例如添加或删除换行符,或添加到预先存在的元素的额外属性)不会破坏您的脚本。

假设您的输入结构如下所示(位于单个父项下,此处称为item,定义了namevalue 之间的关系):

<config>
  <item><name>abcdef</name><value>123456</value></item>
  <item><name>fedcba</name><value>654321</value></item>
</config>

...您可以像这样编辑它:

 # edit the value under an item having name "abcdef"
 xmlstarlet ed -u '//item[name="abcdef"]/value' -v "new-value"

如果是这样(名称/值对之间的顺序描述它们的关系):

<config>
  <name>abcdef</name><value>123456</value>
  <name>fedcba</name><value>654321</value>
</config>

...然后你可以像这样编辑它:

# update the value immediately following a name of "abcdef"
xmlstarlet ed -u '//name[. = "abcdef"]/following-sibling::value[1]' -v new-value

【讨论】:

    【解决方案2】:

    只要数据中有标签->值对,最好在代码中创建标签->值数组:

    $ awk -F'[<>]' '{tag=$2; v[tag]=$3} tag=="value" && v["name"]=="abcdefg" {sub(/>.*</,">blahblah<")} 1' file
    <name>abcdefg</name>
    <value>blahblah</value>
    

    【讨论】:

    • 从 XML 合规性的角度来看,这段代码的表现并不是很好。例如,每行一个元素的假设意味着这对于大量格式良好的文档来说会很糟糕;也无法识别内容是否被注释掉。此外,在 XML 中,在某些情况下,&lt;s 可以而且将是文字而不是语法——例如,CDATA 部分。
    • 同意。似乎我们在这里得到的关于解析 XML 的大多数问题实际上都是关于解析以非常有限的方式使用的 XML,因此 awk 或其他解决方案通常就足够了,但是您可以为不引用 shell 变量等做出同样的情况,所以 YMMV。
    【解决方案3】:

    使用的样本数据:

     cat key
    <name>abcdaaefg</name>
    <value>123456</value>
    <name>abcdefg</name>
    <value>123456</value>
    <name>abcdaaefg</name>
    <value>123456</value>
    

    sed解决方案:

     sed '/abcdefg/!b;n;c<value>OLA<value>' key
    
    <name>abcdaaefg</name>
    <value>123456</value>
    <name>abcdefg</name>
    <value>OLA<value>
    <name>abcdaaefg</name>
    <value>123456</value>
    

    用于更改文件。

    sed -i.bak '/abcdefg/!b;n;c<value>OLA<value>' key
    

    awk解决办法:

    awk '/abcdefg/ {print $0;getline;sub(/>.*</,">ola<")} {print $0}' key
    <name>abcdaaefg</name>
    <value>123456</value>
    <name>abcdefg</name>
    <value>ola</value>
    <name>abcdaaefg</name>
    <value>123456</value>
    

    搜索包含abcdefg 的行,然后执行以下操作:
    1. 打印那行,
    2.移至下一行并将html标签内的值替换为其他内容。在这里,我将123456 替换为ola

    【讨论】:

    • 您好,感谢您的快速回复。但是如何替换文件中的文本。
    • 使用 sed -i ,这称为就地替换,将对您的原始文件进行更改。如果你想保留你的文件的备份然后sed -i.bak
    • 为了改善答案,您可以澄清'/abcdefg/!b;n;c&lt;value&gt;OLA&lt;value&gt;'
    • 鉴于各种输入文件,getline 将以神秘的方式失败,并且将使未来的增强变得困难(例如,尝试为每个包含数字的输入行添加调试 print,并注意您必须复制它),因此通常最好避免使用它,除非在极少数特定情况下它会增加一些实际价值。见awk.freeshell.org/AllAboutGetline
    猜你喜欢
    • 1970-01-01
    • 2012-08-22
    • 1970-01-01
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多