我有一个包含 12,000 多个 XML 文件的文件夹。我需要获取该文件夹中满足特定条件的文件列表。
在 XML 文件中,有一个名为 的节点/BillingData/InvoiceLinesList/InvoiceLines
。InvoiceLines
内可能有一个或多个InvoiceLinesList
。在 中InvoiceLines
,我需要搜索一个名为 的标签,<charge>
其值为,以及同一个名为99
的标签中有一个标签,其值为。InvoiceLines
<chargeType>
D
最好的方法是什么?使用awk
我认为我也许能够做到这一点,但我无法找到一种搜索多个条件的方法,因为我不擅长awk
。我在这里看到了一种潜在的方法,xmlstarlet
但它只在单个标签中查找一个或其他值,而不是在多个标签中查找单独的值。
答案1
和通常都不适合解析 XML(以及其他类似格式awk
,sed
例如 JSON 和 YAML 等)。例如,对于这个 XML 示例,我们不知道节点的InvoiceLines
存储顺序或它们是否由换行符分隔。 XML 格式不关心这些事情,但是awk
orsed
脚本很容易失败,除非特别小心地覆盖所有可能的情况(包括数据的各种可能的编码),在这种情况下,您将不得不编写一个 XML无论如何解析器。
因此,使用 XML 解析器(如内置的解析器xmlstarlet
)是正确的做法。
如果在文件中至少找到一个所需的节点,以下命令将打印输入文件的文件名file.xml
。如果多个InvoiceLines
节点匹配,文件名将被打印多次,中间有换行符。这意味着我们从一开始就取消包含换行符的文件名。
xmlstarlet sel \
-t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
--inp-name -nl file.xml
XPATH 查询将匹配所有InvoiceLines
具有子节点chargeType
并charge
具有指定值的节点。使用@charge
而不是charge
针对一个进行测试charge
属性InvoiceLines
顺便说一句,在节点中。
将其应用于单个目录中的所有 XML 文件:
xmlstarlet sel \
-t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
--inp-name -nl ./*.xml
如果文件太多并且上面抛出错误,您可以使用xargs
:
printf '%s\n' ./*.xml | xargs xmlstarlet -t -m ...
或者,find
(这也将搜索子目录):
find . -type f -name '*.xml' -exec xmlstarlet -t -m ... {} +
uniq
如果您想让文件列表唯一,则通过管道传输结果。
我使用以下 XML 来测试上述内容:
<BillingData>
<InvoiceLinesList>
<InvoiceLines>
<chargeType>D</chargeType>
<charge>99</charge>
</InvoiceLines>
<InvoiceLines>
<chargeType>D</chargeType>
<charge>99</charge>
</InvoiceLines>
<InvoiceLines>
<chargeType>E</chargeType>
<charge>99</charge>
</InvoiceLines>
</InvoiceLinesList>
</BillingData>