删除具有空属性的 XML 标签

删除具有空属性的 XML 标签

输入文件:

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

这会在看到该行时保存带有起始标记的行。当读取下一行时,如果我们有已保存的行但当前行是结束标记,那么我们会抑制这两者。否则打印保存的行,然后打印当前行。

相关内容