【问题标题】:How can I add a value to a tag in an XML-like file from within a BASH script?如何从 BASH 脚本中将值添加到类似 XML 的文件中的标记?
【发布时间】:2014-07-14 22:16:25
【问题描述】:

我有一个名为 metadata.xml 的文件,其中包含(唯一)标签 MissingVal 等等:

metadata.xml:

<foo1>
    someData
</foo1>
<foo2>
    123.54
</foo2>
<MissingValue>

</MissingValue>
<foo3>
    1.0
</foo3>

我正在使用 BASH 脚本来处理这个文件。在脚本中,我将变量 SomeVal 设置为数字“真实”值:SomeVal=1234567890.0

如何让我的 BASH 脚本将 SomeVal 的值写入 metadata.xml 文件中的 &lt;MissingValue&gt; 标记?运行脚本应该使metadata.xml 如下所示:

metadata.xml:

<foo1>
    someData
</foo1>
<foo2>
    123.54
</foo2>
<MissingValue>
    1234567890.0
</MissingValue>
<foo3>
    1.0
</foo3>

我想我可以使用awksed 来执行此操作,但我对这些程序还不够熟悉,无法取得很大进展。

提前致谢!

【问题讨论】:

  • 我不确定有没有一种漂亮的方法可以用 shell 做到这一点。请改用一些工具,例如 c++ 中的 libxml 或 python 中的 ElementTree

标签: xml bash shell awk sed


【解决方案1】:
sh$ export SomeVal=1234567890.0
sh$ perl \
     -0pe \
     "s|<MissingValue>\s*</MissingValue>|<MissingValue>$SomeVal</MissingValue>|sg" \
     metadata.xml

制作:

<foo1>
    someData
</foo1>
<foo2>
    123.54
</foo2>
<MissingValue>1234567890.0</MissingValue>
<foo3>
    1.0
</foo3>

【讨论】:

  • 太棒了!太感谢了!我最终使用的几乎是 - 我添加了换行符并将其重定向到同一个文件:cat metadata.xml | perl -0pe "s|&lt;MissingValue&gt;\s*&lt;/MissingValue&gt;|&lt;MissingValue&gt;\\n$SomeVal\\n&lt;/MissingValue&gt;|sg" &gt;&gt; metadata.xml
  • 你不应该将cat与可以自己读取数据的程序一起使用,例如perlawksed
  • @Jotne 当然。我使用cat(或多或少系统地)以清楚地显示数据流。当您不习惯 shell 编程时,使用标准输入重定向 (&lt;) 的可读性较差,因为它“隐藏”了表达式右侧的源代码——而将源代码放在左侧和感觉更自然右边的目的地(因为这是由 pipe 语法暗示的)。我知道有人可能不同意这一点。
  • 这里的前辈都会跟我说一样的。它使用更多资源,并且会减慢速度。而且您还将在FILENAME 中的awk 等程序中失去功能。对于其他人来说,最好先展示最好的方法。如果您想用cat 显示它,请同时发布并解释它只是为了显示流程,您不应该使用它。
  • @Jotne 完成。为了将源文件隐藏在“代码滚动窗口”之外,我也更改了格式
【解决方案2】:

不要使用 shell,不要使用 awk,不要使用 sed,不要使用任何其他文本处理工具。使用 xsltproc 或其他为处理 xml 而设计的类似工具。

使用具有单个根节点的正确构造的 xml 文档,以下转换将在以 xsltproc --stringparam SomeValue "$SomeVal" metadata.xsl metadata.xml 运行时执行您想要的操作

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="SomeValue"/>

    <!-- Whenever you match any node or any attribute -->
    <xsl:template match="@*|node()">
        <!-- Copy the current node -->
        <xsl:copy>
            <!-- Including any attributes it has and any child nodes -->
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="MissingValue">
        <xsl:copy>
            <!-- Including any attributes it has and any child nodes -->
            <xsl:apply-templates select="@*"/>
            <xsl:text>
    </xsl:text>
            <xsl:value-of select="normalize-space($SomeValue)"/>
            <xsl:text>
</xsl:text>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

我绝不是 xslt 专家,所以可能有更好的方法来做到这一点。

【讨论】:

  • 谢谢。然而,在我的情况下,我认为我需要在某种程度上使用 BASH。我的 BASH 脚本解析其他非 XML 文件以获取我需要放入 MissingValue 标记中的变量 someVal 的值。我怀疑xsltproc 可以读取自定义格式的文件,但即使可以,我在 BASH 中有很多现有代码我宁愿不学习xsltproc 并翻译我现有的代码。不过,我很高兴尝试使用xsltprox。您知道如何我可以从我的脚本中调用xsltproc,以便它从BASH 中获取值并将其放入MissingValue 标记中吗?
  • @jvriesem xsltproc 支持通过命令行传递参数,因此这是获取值的一种完全有效的方式。我什至编写了 xsl 来做到这一点。唯一的问题是您的输入 xml 文档对于 xslt 不是“有效的”,因为它没有单个根元素。
【解决方案3】:

这里是使用awk的方法

SomeVal=1234567890.0
awk '/<MissingValue>/ {$0=$0"\n    "v}1' v="$SomeVal" metadata.xml
<foo1>
    someData
</foo1>
<foo2>
    123.54
</foo2>
<MissingValue>
    1234567890.0

</MissingValue>
<foo3>
    1.0
</foo3>

【讨论】:

    猜你喜欢
    • 2021-03-14
    • 2019-10-24
    • 2020-06-10
    • 2015-03-31
    • 1970-01-01
    • 2018-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多