12,000を超えるXMLファイルを含むフォルダがあります。このフォルダから特定の基準を満たすファイルのリストをインポートする必要があります。
XMLファイルにはというノードがあります/BillingData/InvoiceLinesList/InvoiceLines
。InvoiceLines
1つ以上がある可能性がありますInvoiceLinesList
。で値のあるInvoiceLines
タグを検索する必要があり<charge>
、名前付きの同じ99
タグ内に値があるタグがあります。InvoiceLines
<chargeType>
D
最良のアプローチは何ですか?を使うとawk
こんなに可能かもしれないと思っていましたが、うまくいかないので、複数の基準で検索する方法が見つかりませんawk
。ここでは潜在的なアプローチを見ることができますが、xmlstarlet
複数のタグで別々の値を見つけるのではなく、単一のタグで1つまたは別の値だけを探します。
答え1
通常、XML(およびJSONやYAMLなどの他の同様の形式)awk
を解析するのには適していません。sed
たとえば、この XML 例では、ノードが保存される順序または改行InvoiceLines
で区切られているかどうかはわかりません。 XML形式はこれらのことを気にしませんが、可能な限り(データ内のすべての可能なエンコーディングを含む)処理に特別な注意を払わない限り、awk
ORスクリプトは簡単に失敗する可能性があります。sed
どのデバイスに関係なく解析されます。
したがって、XMLパーサー(組み込みパーサーなどxmlstarlet
)を使用することは正しいアプローチです。
次のコマンドは、ファイルに1つ以上の必須ノードが見つかると、入力ファイルのファイル名を印刷しますfile.xml
。複数のInvoiceLines
ノードが一致する場合、ファイル名は、間に改行を含む複数回印刷されます。これは、最初から改行文字を含むファイル名を抑制することを意味します。
xmlstarlet sel \
-t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
--inp-name -nl file.xml
XPATHクエリは、指定された値を持つ子ノードを持つすべてのInvoiceLines
ノードと一致します。 1つをテストする代わりに使用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>