【问题标题】:Substring replacement inside XML values with XMLStarlet使用 XMLStarlet 替换 XML 值内的子字符串
【发布时间】:2015-10-28 09:23:39
【问题描述】:

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

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

例如,我有以下 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 的工具来实现。

这里的任何帮助将不胜感激!

【问题讨论】:

  • 在未来,请考虑对您的问题进行简洁、中肯的总结,并明确提出,这样您就不必阅读大量文字即可了解您的问题试图做。引用catb.org/esr/faqs/smart-questions.html——数量不精确!
  • 抱歉...感谢您的帮助

标签: xml bash xpath cdata xmlstarlet


【解决方案1】:

提供一个表达式(带有-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 版本,因此该表达式比其他情况下可能有点笨拙。

【讨论】:

  • 谢谢,这可以更改特定值,然后连接字符串的其余部分,但是我需要能够单独修改 strval 字段中的每个值...
  • 您的问题是否表明某处需要? (再看一遍:足够长以至于不容易阅读)。
猜你喜欢
  • 2018-03-05
  • 2019-01-09
  • 1970-01-01
  • 2023-04-05
  • 2015-03-27
  • 1970-01-01
  • 1970-01-01
  • 2017-03-23
  • 2022-12-30
相关资源
最近更新 更多