问题描述:
考虑以下XML文件:
<xmlhead1> <xmlsubhead1> <record> <field>Hello</field> <field>World</field> </record> <record> <field>DELETEKEY</field> <field>World1</field> </record> </xmlsubhead1> </xmlhead1>
我的目标是在字段子标记时删除“记录”XML标记 该XML节点包含DELETEKEY作为值。
所以在上面的XML文件中我将删除
<record> <field>DELETEKEY</field> <field>World1</field> </record>
解决方案选择
我尝试使用 GNU sed 来解决上述问题:
以下是我的代码。
sed -n '
/<xmlhead1>/,/<\/xmlhead1>/{
/<xmlsubhead1>/,/<\/xmlsubhead1>/{
/<record>/,/<\/record>/{
#Append to hold space
H
#if match DELETEKEY, start delete processing for the xml <record> element
/<field>DELETEKEY<\/field>/{
s/.*//g ; x
b delete
}
#if you have reached the end tag of the <record> element,
#print the hold space and clear the buffers
/<\/record>/{
g ; s/^\n//g; p
s/.*//g ; x ; s/.*//g
}
#continue to next line
b
#delete processing
:delete
{
#clear pattern space.
s/.*//g
#Read Next Line and remove new line(\n)
N
s/^\n//g
#end delete processing when line matches the end tag </record>
/<\/record>/b
#else continue to get next line for delete process
b delete
}
}
}
}
#print all other lines
p
' $inputfile
逻辑如下:
- 匹配地址范围以
开头<xmlhead1> and ending with </xmlhead1>
- 匹配以...开头的内部地址范围
<xmlsubhead1> and ending with </xmlsubhead1>
- 匹配内部地址范围
<record> to </record>
- 在
醇><record>
标记内,
(i)将所有线路附加到保留空间 (ii)如果该行匹配DELETEKEY
,则必须删除该记录。执行步骤iii和iv。否则,如果没有匹配,请转到步骤v
(iii)对于删除,清除保留空间并跳转到删除分支
(iv)在删除分支中,使用“N”命令读取所有下一行,直到遇到</record>
。当</record>
时 遇到,退出循环并开始处理下一个 行。
(v)当不处理删除逻辑时,如果遇到</record>
,则表示<record> to </record>
的块 成功处理并存在于保留空间中 (vi)将其从保持空间中取出并打印出来。
输出上述逻辑:
<xmlhead1>
<xmlsubhead1>
<record>
<field>Hello</field>
<field>World</field>
</record>
</xmlhead1>
输出中的问题:
您可以注意到删除了带有DELETEKEY的记录元素,但输出中缺少</xmlsubhead1>
标记。
问题调试:
在调试时,我发现在删除处理中遇到</record>
行后,在<record> to </record>
范围内,内部地址范围匹配应该已经结束,因为我已经阅读并处理了</record>
行。
但<record> to </record>
范围块似乎也处理</xmlsubhead1>
行。
我通过在<record>
范围的命令块中添加以下代码找到了这个。
/<record>/,/<\/record>/{
/<\/recordList>/{
s/.*/record list is inside the record to record range/g
p
}
有人可以解释sed的这种行为,范围匹配超过实际匹配吗?在这种情况下<record> to </record> range match is also matching </xmlsubhead1>
答案 0 :(得分:1)
不要使用sed编辑XML,请使用支持XML的工具。例如,在xsh中,您可以写:
open file.xml ;
delete //record[field="DELETEKEY"] ;
save :b ;
答案 1 :(得分:0)
我同意有关使用正确的XML解析器的评论。
您的sed脚本存在的问题是您在N
“函数中读取了{:delete
)行”。这是一个使用更简单逻辑的工作示例:
/<xmlhead1>/,/<\/xmlhead1>/{
/<xmlsubhead1>/,/<\/xmlsubhead1>/{
/<record>/ {
:a
N
/<\/record>/!ba
/<field>DELETEKEY<\/field>/d
}
}
}
p
即。在正确的上下文中,读取完整记录(假设简化的XML结构),如果记录包含违规文本,则将其删除。