首页 > 解决方案 > 如何使用 Sed 和 Awk 在 XML 中将一个属性替换为另一个属性

问题描述

我有一个包含很多 XML 节点的文件:

<output>
<file name="user.java">
</file>

<file name="random.java">
<error line="52" column="3" severity="warning" message="User is not found." source="randomSource"/>
</file>
<output/>

现在我需要将source错误节点中的替换为name文件中的属性并将其打印到文件中。所以输出文件应该有only几行错误:

<error line="52" column="3" severity="warning" message="User is not found." name="customer.java"/>

最好名称应该是第一个属性:

<error name="random.java" line="52" column="3" severity="warning" message="User is not found." />

所以新文件应该只包含错误节点,我只能使用默认工具,如 sed/awk/cut/etc...

我只打印了错误行,但不知道如何执行上述操作:

awk -vtag=file -vp=0 '{
if($0~("^<"tag)){p=1;next}
if($0~("^</"tag)){p=0;printf("\n");next}
if(p==1){$1=$1;printf("%s",$0)}
}' infile 

标签: awksed

解决方案


试试这个简单的awk程序:

level == 0 && $0 ~ "<" tag ".*>" {
    print
    level++
    # get "name" attribute
    gsub(/^.*name="/, "")
    gsub(/".*$/, "")
    name = $0
    next
}
level == 1 && /<error.*>/ {
    # remove "source" attribute
    gsub(/ source="[^"]*"/, "")
    # put "name" attribute at the beginning of "error" tag
    gsub(/<error /, "<error name=\"" name "\" ")
    print
    next
}
level == 1 && $0 ~ "</" tag ">" {
    print
    level--
    next
}
{
    print
}

像这样调用:

$ cat xmlerr.xml | awk -v tag="file" -f xmlerr.awk 
<output>
    <file name="user.java">
    </file>
    
    <file name="random.java">
    <error name="random.java" line="52" column="3" severity="warning" message="User is not found."/>
    </file>
</output>

删除不必要的print命令

选择

name如果你想在打开的“ ”标签中抑制“ ”属性file,第一个块变成:

level == 0 && $0 ~ "<" tag ".*>" {
    name = $0
    level++
    n = gsub(/^.*name="/, "", name)
    gsub(/".*$/, "", name)
    # if substitution done, remove "name" attribute in the original line before printing
    if (n > 0) {
        gsub(/ name="[^"]*"/, "")
    }
    print
    next
}

和输出:

<output>
    <file>
    </file>
    
    <file>
    <error name="random.java" line="52" column="3" severity="warning" message="User is not found."/>
    </file>
</output>

推荐阅读