【问题标题】:Need help in shell scripting to find and replace value in xml file在 shell 脚本中需要帮助来查找和替换 xml 文件中的值
【发布时间】:2018-03-07 21:06:41
【问题描述】:

我有以下 XML 格式

<object class="Class A">
<directory>someString1</directory>
<attr>
     <name>length</name>
     <value>6</value>
 </attr>
 <attr>
     <name>parent</name>
     <value>1</value>
 </attr>
 <attr>
     <name>Status</name>
     <value>1</value>
 </attr>
 <attr>
     <name>className</name>
     <value>Class A</value>
 </attr>
 <attr>
     <name>Instance</name>
     <value>InstanceValue</value>
 </attr>
 </object>
 ...
 <object class="Class D">
 <directory>someString4</directory>
 <attr>
     <name>length</name>
     <value>8</value>
 </attr>
 <attr>
     <name>parent</name>
     <value>1</value>
 </attr>
 <attr>
     <name>Status</name>
     <value>1</value>
 </attr>
 <attr>
     <name>className</name>
     <value>Class D</value>
 </attr>
 <attr>
     <name>Instance</name>
     <value></value>
 </attr>
 </object>
 ....

我只需要查找特定的 D 类对象并查找该对象的 Instance 值是否为空,如果为空,则使用作为参数提供的某个值填充。请注意,XML 文件中可以有多个对象,并且 XML 标记的名称和值相当重复。此外,我只需要在 suse Linux 上使用 shell 脚本。

我是 shell 脚本和 SED 的新手。我尽力在stackoverflow中找到现有的问题和答案,但找不到相关的问题和答案。 非常感谢任何帮助。

【问题讨论】:

  • 我建议使用 XML/HTML 解析器 (xmlstarlet, xmllint ...)。
  • 请将有效的 xml 文件和该示例的所需输出发布到您的问题中。
  • 当你说“我只需要使用 shell 脚本”时,你能澄清一下你有什么样的限制吗?通常这意味着“我不能安装任何额外的软件”,但有时它意味着“不允许使用 perl 和 python”,甚至“只允许使用 shell 和简单的命令,如 grep 和 sed 以及他们在课堂上教给我们的任何其他命令”。
  • 明确地说,做到这一点的最佳方法涉及真正的 XML 解析器。其中许多都可以从命令行获得(包括xsltproc,如今许多 Linux 发行版都在提供开箱即用的服务)。

标签: xml linux shell sed scripting


【解决方案1】:

如果你可以使用xmlstarlet,你可以这样做:

xml ed -L -u "//object[@class='Class D']/attr[name='Instance'][value='']/value" -v "new value" input.xml

注意:-L 就地编辑文件。如果不需要,请将其删除。

或者,您可以使用xsltproc 通过 XSLT 处理 XML:

xsltproc -o output.xml stylesheet.xsl input.xml

stylesheet.xsl 在哪里:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="object[@class='Class D']/attr[name='Instance' and value='']/value">
    <xsl:copy>
      <xsl:text>new value</xsl:text>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

【讨论】:

  • 您还可以讨论使用 xmlstarlet 构建 XSLT 模板,然后该模板可以在没有安装 xmlstarlet 本身的系统上运行。
  • (OP 在问题中指出他们正在使用 SuSE,它将 xsltproc 作为 libxslt 包的一部分提供——因此它在基线安装中是开箱即用的。因此, xmlstarlet 可能存在也可能不存在于 OP 的目标环境中,但 xsltproc 肯定存在)。
  • @CharlesDuffy - 好点。我添加了一个 xsltproc 示例。如果 OP 希望我讨论使用 xmlstarlet 构建 XSLT 样式表,我可以。
【解决方案2】:

你能检查它是否按你的需要工作吗?

#!/bin/bash

VALUE="NewValue"
sed -i data.xml -re "
/Class D/,/<\/object>/ {
    /<name.*>Instance<\/name>/,/<\/value>/ {
        s/(<value.*>)(<\/value>)/\1${VALUE}\2/
    }
}
"

它应该找到你的类,然后找到名称“Instance”,如果没有值则插入新值,否则它不应该做任何事情

【讨论】:

  • 并且不要忘记在运行脚本之前备份您的 XML 文件,它会在不询问的情况下更改文件
  • 这种方法天生就脆弱。它无法理解 cmets,它无法理解 CDATA 部分,它无法理解命名空间(因此,在文档的某个部分中,name 可以真正表示 {http://example.com/some/namespace/prefix}name);它甚至无法理解 &lt;name foo="example"&gt;&lt;name&gt; 的超集。当客户执行这种脆弱的处理时,运行生成 XML 输出的服务的人们讨厌它,因为这意味着我们每次更改某些内容时都会收到投诉,即使新文档在语义上是旧文档的适当超集。
  • 同意。我自己会推荐 xmlstarlet 之类的东西,但是 1)问题的作者说他只需要 shell 脚本,2)问题中给出的数据是可以的。如果他需要更复杂的东西,他应该提供更多信息
猜你喜欢
  • 1970-01-01
  • 2012-09-13
  • 2013-06-21
  • 1970-01-01
  • 2012-06-07
  • 2013-04-23
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
相关资源
最近更新 更多