【问题标题】:Use sed to duplicate a line in an xml and keep the same indentation使用 sed 在 xml 中复制一行并保持相同的缩进
【发布时间】:2014-10-30 11:57:30
【问题描述】:

我正在尝试为大量 xml 文件批量添加新标签。

一个示例xml如下:

<attribute name="MyAttribute">
    <type>
        <long>
            <range>
                <min>0</min>
                <max>100000</max>
            </range>
            <defaultValue>0</defaultValue>
        </long>
    </type>
</attribute>

在上面的示例中,我有一个带有一定缩进的“类型”标签。我希望能够做到以下几点:

  1. 查找此“类型”标签的所有实例
  2. 复制标签所在的行,包括缩进(The 整个文件的缩进不一致,因此不能是 硬编码值)
  3. 在“type”上方粘贴一个新标签,例如“myAddedTag” 标记并保持缩进

预期结果:

<attribute name="MyAttribute">
    <myAddedTag>
    <type>
        <long>
            <range>
                <min>0</min>
                <max>100000</max>
            </range>
            <defaultValue>0</defaultValue>
        </long>
    </type>
</attribute>

我一直在使用 sed 在 shell 脚本中查找类型标记并将其替换为类似以下命令的内容,但我的问题是缩进 - 我似乎不知道如何维护它。我尝试添加空格,但所有文件的缩进都不相同。

sed 命令示例如下: 文件:my_sample_sed_script.sh

#!/usr/bin/env bash
sed -i "s/<type>/<myAddedTag \/>\n<type>/g"  $1

我在 bash 中使用这个命令调用脚本:

my_sed_script.sh sample.xml

但是,输出如下——看类型标签没有缩进:

<attribute name="MyAttribute">
        <myAddedTag>
<type>
            <long>
                <range>
                    <min>0</min>
                    <max>100000</max>
                </range>
                <defaultValue>0</defaultValue>
            </long>
        </type>
    </attribute>

任何帮助将不胜感激。正如我所提到的,我的问题是试图找到一种解决方案,使缩进与我正在复制/替换的行相同。

【问题讨论】:

    标签: xml regex bash shell sed


    【解决方案1】:

    不要使用sed 处理 XML。

    使用像 xsltproc 这样的 XML 感知工具和这个 XSLT 样式表:

    <!-- add_attribute.xsl -->
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <!-- copy everything ... -->
        <xsl:template match="node() | @*">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*" />
            </xsl:copy>
        </xsl:template>
    
        <!--  <attribute name="MyAttribute"> special case -->
        <xsl:template match="attribute[@name='MyAttribute']">
            <!-- copy element and its attributes -->
            <xsl:copy>
                <xsl:apply-templates select="@*" />
    
                <!-- copy first, whitespace-only text node (i.e. the indentation) -->
                <xsl:copy-of select="text()[1][normalize-space() = '']" />
    
                <!-- add your tag -->
                <myAddedTag />
    
                <!-- copy rest of the contents -->
                <xsl:apply-templates select="node()" />
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    用法:

    xsltproc add_attribute.xsl your_file.xml

    输出:

    <attribute name="MyAttribute">
        <myAddedTag/>
        <type>
            <long>
                <range>
                    <min>0</min>
                    <max>100000</max>
                </range>
                <defaultValue>0</defaultValue>
            </long>
        </type>
    </attribute>
    

    好处是在结构上破坏 XML 的可能性为零,而您可以以比正则表达式更易于维护和灵活的方式进行复杂的修改。

    【讨论】:

    • 太棒了,我不知道这个功能。我有多个 xml,具有大量不同的属性名称,并且某些属性具有超过指定的标签。您对我如何跨不同的属性名称实施此解决方案有任何建议吗?
    • 您可以轻松地扩展 XSLT 样式表。只需为您必须处理的每个特殊情况添加一个&lt;xsl:template&gt;。复制我制作的模板,调整匹配表达式,更改内容。您可以在同一个 XSLT 文件中拥有任意数量的模板,一个用于输入中的每种情况的模板,轻松满足您的所有不同需求。
    • xslt 中唯一特定于该更改的部分是 match 语句和添加的标签本身。剩下的只是“框架”。您可以将其中任何一个更改为您想要的任何内容。您甚至可以在同一个 xslt 中拥有多个不同的 &lt;xsl:template&gt; 节,它们对不同的输入元素执行不同的操作。
    • 感谢所有帮助 - 我会在之前给出这个,因为它显然是更强大的解决方案。谢谢!
    • 遇到具体问题时,请不要犹豫。 XSLT 有一个学习曲线,因为它与“通常”的编程语言完全不同。如果您经常使用 XML,那么最终值得付出努力。就像如果你经常处理文本,学习正则表达式是值得的。
    【解决方案2】:

    你可以用这个sed

    sed 's/^\(\s\+\)<type>/\1<myAddedTag \/>\n&/g' yourfile
    

    【讨论】:

    • 这似乎很适合我想要的 - 谢谢
    【解决方案3】:

    如果你愿意为你的任务使用 perl 或 python,你可以使用它。

    (.+?)(?=(\s*)<type>)(.*)$
    

    试试这个。这会保留缩进。

    查看演示。

    http://regex101.com/r/oC3nN4/2

    【讨论】:

    • 这只会给文件添加一个标签,OPs版本支持多个标签。我不知道这是否是一个要求。
    • @EtanReisner 也可以使用前瞻来包含。但是 OP 想要在 sed 中。所以这可能会给出一个提示。
    • 不需要 sed - 我只是认为这是最好的方法。我可以使用任何东西,只要它可以自动在多个 xml 文件上运行。我还需要将此添加到一个文件中的多个标签
    • 另外,我现在正在尝试这个命令(顺便感谢一下),但我遇到了一个错误——你能指出我正确的方向吗?新脚本: sed 's/(.+?)(?=(\s*))(.*)$/$1\2$3/g' sample.xml 我收到此错误:sed: -e 表达式 #1,字符 48:`s' 命令的 RHS 上的无效引用 \2 @EtanReisner
    • 错误是什么,你是如何实现的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 2015-08-08
    • 1970-01-01
    • 2015-07-01
    相关资源
    最近更新 更多