输入文件:
<ServiceArea type="STATE" value="DC">
<DaylightSavingsUsed value="true"/>
<FemtoSipProxyAddress value="10.13.123.100"/>
<TermAuthAAAPSK value="secret1"/>
<PDSNDOParams index="1">
<batchEndIpAddress value="68.28.121.68"/>
<batchSecurityParameterIndex value="5262006"/>
<batchStartIpAddress value="68.28.121.68"/>
</PDSNDOParams>
<PDSNDOParams index="2">
<batchEndIpAddress value="68.28.113.68"/>
<batchIOSVersion value="tia-878-a"/>
<batchStartIpAddress value="68.28.113.68"/>
</PDSNDOParams>
<PDSN1XParams index="1">
<batchEndIpAddress value="68.28.121.68"/>
<batchSecretKey value="72563130317354663167345439615433"/>
<batchSecurityParameterIndex value="5262006"/>
<batchStartIpAddress value="68.28.121.68"/>
</PDSN1XParams>
<PDSN1XParams index="2">
<batchEndIpAddress value="68.28.113.68"/>
<batchIOSVersion value="tia-878-1"/>
</PDSN1XParams>
</ServiceArea>
<ServiceArea type="ZIP" value="66221">
</ServiceArea>
<ServiceArea type="FIPS" value="46081">
<DaylightSavingsUsed value="true"/>
<MTA_Number value="22"/>
<BC10_Utilization value="476,487,526"/>
</ServiceArea>
<ServiceArea type="FIPS" value="01824">
</ServiceArea>
我想删除所有之间没有数据的行
<ServiceArea type=
</ServiceArea>
在上面的输入中我需要删除:
<ServiceArea type="ZIP" value="66221">
</ServiceArea>
和
<ServiceArea type="FIPS" value="01824">
</ServiceArea>
答案1
您可以xsltproc
通过xslt
脚本(又名样式表)来处理 XML 文件。它将涉及 xslt 脚本和控制 bash 脚本。例如:
drompem.xslt
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="ServiceArea">
<xsl:if test="count(*)>0">
<ServiceArea>
<xsl:copy-of select="node()"/>
</ServiceArea>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
dropem.sh
#!/bin/bash
cat <<EOF | xsltproc dropem.xslt - | tail -n +2
<ALL>
$(cat)
</ALL>
EOF
实际的命令将是
./dropem.sh < infile > outfile
注意:该xslt
脚本包含一个与您的 ServiceArea 节点匹配的“模板”元素,并有条件地(如果它有子节点)将其复制到结果中。
输入需要包装到封闭的标记对中,因为xsltproc
仅处理单个 XML 树。包装使您的数据文件成为一棵树。输出不会保留换行,输出也是 ServiceArea 子树的列表。
然而,输出被修剪以避免不可避免地发出<?xml ...
前导码和空行。xsltproc
这种方法的优点是它对输入文件行格式不太敏感。缺点是它使用了xslt
一种不太常见的语言。
答案2
您可以通过xmlstarlet
不同的方式来执行此操作,具体取决于您想要如何检测ServiceArea
节点:
删除所有
ServiceArea
“文本节点”节点:xmlstarlet ed -d '//ServiceArea[text()]' file.xml
删除所有
ServiceArea
具有零个子节点的节点:xmlstarlet ed -d '//ServiceArea[count(*)=0]' file.xml
这两者都取决于您的文档是否格式良好。您的示例文档不是这样,因为它包含多个根节点。解决这个问题很简单,只需<root>
在文档的开头和</root>
结尾处添加例如即可。
答案3
每个人都会告诉您使用正确的 xml 解析工具来编辑 xml,但这里有一个简单的 awk 脚本,它假设(如您的示例中所示)ServiceArea 标记单独位于单独的行上:
awk '/<ServiceArea /{save = $0; next}
save!="" {
if(/<\/ServiceArea>/){ save = ""; next }
print save
save = ""
}
{ print }'
这会在看到该行时保存带有起始标记的行。当读取下一行时,如果我们有已保存的行但当前行是结束标记,那么我们会抑制这两者。否则打印保存的行,然后打印当前行。