【问题标题】:Modify xml file with shell script使用 shell 脚本修改 xml 文件
【发布时间】:2021-08-10 13:43:27
【问题描述】:

我有一个包含大量 XML 代码的文件,我想用某个值修改该文件的一部分。

例子:

假设我有很多名为 target 的标签,我想搜索某个名称来进行修改。

<target name="forest US" description="have more species" >
    <modification.start.yes/>
    <modif.fr.ss type="Animals" color="brown" outputFile="New_type.csv" />
    <modification.end.yes/>
</target>

我想要做的是在我的 XML 文件中搜索名称为 forest US 的标签,将类型从 Animals 更改为 Plants em> 例如 以及从 New_type.csvOld_type.csv 的输出文件。

我尝试使用这个 sed 命令:

(一般的命令)

sed 's#&lt;target name="forest US" description="have more species"&gt;.*#&lt;target name="forest US" description="have more species"&gt;SOMETHING&lt;/target&gt;#' file.xml

我想知道是否有其他方法,因为这个方法不能正常工作。

谢谢!

【问题讨论】:

  • 使用 XSLT 转换是一项非常简单的任务。

标签: xml bash shell file tags


【解决方案1】:

(此答案并非垃圾邮件,只是一般性评论)

尝试使用标准命令和工具(grepsedawk、...)来操作特殊格式(XMLJSON)是一个典型的错误,但这是一个坏习惯:您可能会破坏格式并使文件无法使用。

最好是寻找常用的工具来执行这些任务:

【讨论】:

    【解决方案2】:

    这里是如何使用 XSLT 来实现您所需要的。

    XSLT 使用所谓的 身份转换 模式。

    您可以使用 xsltproc Saxon 进行实际的 XSLT 转换。

    输入 XML

    <?xml version="1.0"?>
    <root>
        <target name="forest US" description="have more species">
            <modification.start.yes/>
            <modif.fr.ss type="Animals" color="brown" outputFile="New_type.csv"/>
            <modification.end.yes/>
        </target>
        <target name="desert US" description="have more species">
            <modification.start.yes/>
            <modif.fr.ss type="Animals" color="brown" outputFile="New_type.csv"/>
            <modification.end.yes/>
        </target>
    </root>
    

    XSLT

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="target[@name='forest US']/modif.fr.ss">
            <xsl:copy>
                <xsl:attribute name="type">Plants</xsl:attribute>
                <xsl:copy-of select="@color"/>
                <xsl:attribute name="outputFile">Old_type.csv</xsl:attribute>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    输出 XML

    <?xml version='1.0' ?>
    <root>
      <target name="forest US" description="have more species">
        <modification.start.yes/>
        <modif.fr.ss type="Plants" color="brown" outputFile="Old_type.csv"/>
        <modification.end.yes/>
      </target>
      <target name="desert US" description="have more species">
        <modification.start.yes/>
        <modif.fr.ss type="Animals" color="brown" outputFile="New_type.csv"/>
        <modification.end.yes/>
      </target>
    </root>
    

    【讨论】:

      【解决方案3】:

      正如其他人已经解释的那样,使用专用的 XML 工具会好得多。以防万一除了sed(不太可能)之外真的没有其他可能性,并且如果您的 XML 非常非常简单(如您所显示的那样):

      sed '/<target name="forest US" description="have more species" >/,/<\/target>/{
        s#type="Animals"#type="Plants"#;
        s#outputFile="New_type.csv"#outputFile="Old_type.csv"#;
      }' file.xml
      

      【讨论】:

      • 非常感谢您的回复,我有一个小问题:如果我不知道我的类型有什么价值,我想将其更改为植物,我的意思是之前不知道type里面有Animals,type后面应该有plants的值?
      • Animals 替换为[^"]*,这意味着:除" 之外的任何字符,零个或多个时间(但尽可能多)。如果您编辑您的问题以反映此更改,我也会编辑我的答案。