【问题标题】:Replace dynamic content in XML file替换 XML 文件中的动态内容
【发布时间】:2012-11-02 10:11:06
【问题描述】:

快速总结:我需要创建一个 Bash 脚本来每周自动更改节点内的文本。脚本将匹配节点并替换其中的文本(如果可能的话)?我该怎么做?

总结: 我托管了一个包含商店的 Minecraft 服务器,每个商店在 /ShowcaseStandalone/ffs-storage/ 目录中都有自己的 .xml 文件。每个星期天我的服务器都会重新启动并在终端中执行几个命令来重置一些东西。我想要改变的一件事是其中一家商店。我想更改节点 中的文本和节点 中的文本。我只是想从不同文件夹中的 .txt 文件中获取文本,并将其插入该节点。问题是,节点中的文本每周都会更改。有没有办法使用 bash 替换两个节点内的特定行或文本?

XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<scs-shop usid="cac8480951254352116d5255e795006252d404d9" version="2" type="storage">
    <enchantments type="string"/>
    <owner type="string">Chadward27</owner>
    <world type="string">Frisnuk</world>
    <itemStack type="string">329:0</itemStack>
    <activity type="string">BUY</activity>
    <price type="double">55.0</price>
    <locX type="double">487.5</locX>
    <locY type="double">179.0</locY>
    <locZ type="double">-1084.5</locZ>
    <amount type="integer">0</amount>
    <maxAmount type="integer">0</maxAmount>
    <isUnlimited type="boolean">true</isUnlimited>
    <nbt-storage usid="23dffac5fb2ea7cfdcf0740159e881026fde4fa4" version="2" type="storage"/>
</scs-shop>

操作系统: Linux Ubuntu 12.04

【问题讨论】:

  • 所以你只是想从 scs-shop 标签更改 usid ?
  • XML 操作仅使用 bash?为什么要限制自己?
  • @sputnick 抱歉,我不得不添加 &lt 和 &gt 标签,因为它杀死了我的节点,但是不,我需要替换节点“itemstack”和“price”中的文本
  • @Brian-Cain 有没有其他方法可以从终端执行此操作?因为这些命令都是在服务器关闭时执行的
  • 我推荐python——你的服务器是否安装了python,或者可以吗?如果没有,java 可能是另一种选择。

标签: xml bash dynamic text replace


【解决方案1】:

您可以使用xmlstarletshell 中编辑XML 文件,如下所示:

xmlstarlet edit -L -u "/scs-shop/price[@type='double']" -v '99.66' file.xml

注意

  • "/scs-shop/price[@type='double']"Xpath 表达式
  • xmlstarlet ed --help

【讨论】:

  • 我并不是要让你为我做所有的工作,但我是一个视觉学习者。我怎么能用它来用“25.0”替换“55.0”?
  • 如果你给我一个有效的 XML,我可以给你完整的语法
  • 你可以这样测试:xmlstarlet val file.xml
  • 那里,我修好了。抱歉,我是 stackoverflow 的新手,所以我不知道如何正确格式化。但它现在应该是一个有效的 xml 文件。
  • 工作就像一个魅力。非常感谢!
【解决方案2】:

XML 方式很酷,但是如果需要使用普通的 bash 工具,可以使用 sed 修改一行。例如:

PRICE=123
sed -i "s/\(<price.*>\)[^<>]*\(<\/price.*\)/\1$PRICE\2/" $XML_FILE_TO_MODIFY

这会将价格替换为 123。

这个 sed 命令似乎令人生畏,所以让我分解一下:

\(&lt;price.*&gt;\)[^&lt;&gt;]*\(&lt;\/price.*\) 是要匹配的模式。 \( ... \) 是用于分组的括号。 &lt;price.*&gt; 匹配开盘价标签。 [^&lt;&gt;]* 匹配除尖括号之外的任何内容,在这种情况下将匹配价格标签的内容。 &lt;\/price.* 匹配价格标签的结尾。正斜杠是 sed 中的分隔符,所以我用反斜杠转义它。

\1$PRICE\2 是要替换匹配文本的文本。 \1 指第一个匹配的括号组,即开盘价标签。 $PRICE 是其中包含所需价格的变量。 \2 指的是第二个括号组,在这种情况下是结束标记。

【讨论】:

  • 这是错误的方式。您无法使用 Bash、grep、sed、cut 等实际解析基于标记的标记语言,例如 HTML 或 XML。请参阅 codinghorror.com/blog/archives/001311.html(您知道 SO 创建者的博客网站吗?)这是关于 HTML,但这是XML 也一样...
  • 如果 linux 带有一个像 xmlstarlet 这样好的 xml 工具,那么我同意这是错误的方法。在此之前,sed 是我的首选工具。实际上,您可以在 99% 的情况下使用 sed,包括这个。
  • 我不是说“那行不通”,而是说:“那不可靠”。在像这样的简单情况下,这对某些人来说似乎“很好”,但是当 XML 会因为嵌套标签变得更加复杂时会发生什么?我说的是让事情变得干净的可靠方法。 sudo apt-get install xmlstarlet 没什么大不了的。
  • “但我认为这与要求由成熟的解析引擎处理每个琐碎的 HTML 处理任务一样错误”是您引用的博客文章的引述。无论如何,记录在案:我更喜欢 xmlstarlet 解决方案。但如果 xmlstarlet 不可用,sed 将完成。
  • @sputnick: apt-get install 不是那么容易,例如你需要一个互联网连接和 HD 上的可用空间(如果你使用 Backtrack 之类的东西,你有一个 4GB 的 ramdisk,如果它已满,它就会崩溃)。最近我的 apt 系统坏了,我 apt-get install 3 个月都不能用!
【解决方案3】:

我没有拥有 xmlstarlet 的奢侈。 我只是通过进行内联替换找到了解决方案;

模板参数.xml

<ns:Parameter>
    <ns:Name required="true">##-ParamName-##</ns:Name>
    <ns:Value>
        <ns:Text>##-ParamValue-##</ns:Text>
    </ns:Value>
</ns:Parameter>

片段

tokenName="foo"
tokenValue="bar"    

#Replace placeholders in parameter template element
myParamElement=$(cat template-parameter.xml)
myParamElement=${myParamElement//##-ParamName-##/$tokenName}
myParamElement=${myParamElement//##-ParamValue-##/$tokenValue}  

结果

<ns:Parameter>
    <ns:Name required="true">foo</ns:Name>
    <ns:Value>
        <ns:Text>bar</ns:Text>
    </ns:Value>
</ns:Parameter>

【讨论】:

  • 那如何再次更改结果文件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 2019-07-07
  • 1970-01-01
  • 2016-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多