使用sed复制xml中的一行并保持相同的缩进

时间:2014-09-05 13:48:13

标签: xml regex bash shell sed

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

示例xml如下:

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

在上面的示例中,我有一个&#34;类型&#34;标记有一定的缩进。我希望能够做到以下几点:

  1. 查找此&#34;类型&#34;的所有实例标签
  2. 复制标记所在的行,包括缩进(The 缩进在整个文件中不一致所以不能是一个 硬编码值)
  3. 粘贴一个新标签,例如&#34; myAddedTag&#34;,在&#34;类型&#34;上方 标记并维护缩进
  4. 预期结果:

    <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>
    

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

3 个答案:

答案 0 :(得分:2)

您可以使用此sed

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

答案 1 :(得分:1)

不要使用sed来处理XML。

使用像xsltproc这样的XML-aware工具和这个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的可能性为零,而你可以用基本上更易于维护和灵活的方式进行复杂的修改,而不是使用正则表达式。

答案 2 :(得分:0)

如果您愿意为您的任务使用perl或python,则可以使用此方法。

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

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

参见演示。

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