xml - 使用 XMLStarlet 替换 XML 值内的子字符串

标签 xml bash xpath cdata xmlstarlet

我正在尝试编辑/更新一些复杂的 XML,遗憾的是我无法更改其格式。我在 Bash 脚本中使用 XMLStarlet。

我遇到困难的是,当我尝试检索或编辑属性的 CDATA 值时,其中属性 "name={name}" 不唯一并返回多个值。

例如,我有以下 XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="key.xsl" ?>
<tables>
  <tableset>
    <table name="table1">
      <row>
        <fld name="fileName">
          <strval><![CDATA[/my/XYZ/file1]]></strval>
        </fld>
        <fld name="fileName">
          <strval><![CDATA[/my/XYZ/file2]]></strval>
        </fld>
        <fld name="fileName">
          <strval><![CDATA[/my/other/XYZ/file3]]></strval>
        </fld>
        <fld name="worksBecauseUnique">
          <strval><![CDATA[/XYZ/unique]]></strval>
        </fld>
      </row>
    </table>
  </tableset>
</tables>

使用 XMLStarlet 时,我可以轻松编辑以下值:

xmlstarlet ed -L \
  -u '//tables/tableset/table/row/fld[@name="worksBecauseUnique"]/strval/text()' \
  -v '/ABC/unique' \
  myxmlfile.xml

但是,在尝试使用属性 name=fileName 修改任何 CDATA 值时遇到问题,因为 fileName 在 XML 中出现多次。

我希望得到如下输出:

<fld name="fileName">
  <strval><![CDATA[/my/ABC/file1]]></strval>
</fld>
<fld name="fileName">
  <strval><![CDATA[/my/ABC/file2]]></strval>
</fld>
<fld name="fileName">
  <strval><![CDATA[/my/other/ABC/file3]]></strval>
</fld>

问题是,如果我尝试使用 XMLStarlet 更新 fileName 的 CDATA 值,如何更新每个值而不更新全部?

例如,如果我运行:

xmlstarlet ed -L \
  -u "//tables/tableset/table/row/fld[@name=\"fileName\"]/strval/text()" \
  -v "/my/ABC/file1" \
  myxmlfile.xml

我得到以下不正确的输出:

<fld name="fileName">
  <strval><![CDATA[/my/ABC/file1]]></strval>
</fld>
<fld name="fileName">
  <strval><![CDATA[/my/ABC/file1]]></strval>
</fld>
<fld name="fileName">
  <strval><![CDATA[/my/ABC/file1]]></strval>
</fld>

请注意每个 CDATA 值如何设置为 "/my/ABC/file1",其中我需要 "/my/ABC/file1", "/my/ABC/file2""/my/other/ABC/file3"

我希望以某种方式允许某人单独修改每个值...... 希望使用任何支持 XPath 的工具都可以实现这一点。

如有任何帮助,我们将不胜感激!

最佳答案

提供一个表达式(使用 -x)将您的输入修改为您想要的输出:

xmlstarlet ed \
  -u '//fld/strval[contains(., "/XYZ/")]' \
  -x 'concat(substring-before(., "/XYZ/"), "/ABC/", substring-after(., "/XYZ/"))'
  <in.xml >out.xml

顺便说一下,新版本的 XPath 标准中有更好的字符串替换函数;由于 libxml(由 XMLStarlet 使用)仅支持版本 1.0,因此该表达式比其他情况下有点笨拙。

关于xml - 使用 XMLStarlet 替换 XML 值内的子字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31835257/

相关文章:

ios - 国家气象局 (NOAA) REST API 为预报参数返回 nil

xml - 将 XML 数据批量插入 SQL Server 2005 数据库的最佳方式

regex - Mac 地址的 Grep 正则表达式

c - Bash/C - 使用其他输出/文件中的值更正脚本输出中的列中的无效值

将多个结果转换为逗号分隔字符串的 WPF XPath 绑定(bind)

xml - 使用 XML 数据源而不是空白页时没有数据时显示 Jasper 报告

r - 从 Word XML 中提取结构化内容

bash - netcat 超时问题

xpath - 如何匹配通过子节点继续的文本序列(例如,使用 sgml 样式标记)?

xml - Metro 应用程序 - 翻译 UI 资源 - 从外部 xml 导入内容