web-dev-qa-db-ja.com

12,000以上のXMLファイルの解析

12,000以上のXMLファイルを含むフォルダーがあります。そのフォルダ内で特定の条件を満たすファイルのリストを取得する必要があります。

XMLファイルには、/BillingData/InvoiceLinesList/InvoiceLinesというノードがあります。 InvoiceLines内に1つ以上のInvoiceLinesListが存在する可能性があります。 InvoiceLinesで、値が<charge>である99というタグを検索する必要があります。また、同じInvoiceLinesに値がDである<chargeType>というタグがあります。 。

それを行うための最良の方法は何ですか? awkを使用すると、それができるかもしれないと思いましたが、awkが得意ではないため、複数の条件を検索する方法がわかりませんでした。ここでxmlstarletを使用する潜在的な方法を見ましたが、それは複数のタグで個別の値ではなく、単一のタグで1つまたは他の値のみを検索します。

1
snert

awksedはどちらも、一般にXML(およびJSONやYAMLなどの他の同様の形式)の解析には適していません。たとえば、このXMLの例では、InvoiceLines内のノードが格納される順序や、改行で区切られているかどうかはわかりません。 XML形式はこれらのことを気にしませんが、awkまたはsedスクリプトは、考えられるすべてのケース(データのさまざまな可能なエンコーディングを含む)をカバーするために特別な注意が払われない限り、簡単に失敗します。 、その場合、とにかくXMLパーサーを作成する必要があります。

したがって、xmlstarletに組み込まれているようなXMLパーサーを使用することは、正しいことです。


次のコマンドは、必要なノードの少なくとも1つがファイル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ノードのInvoiceLinesattributeに対してテストされます。

これを単一のディレクトリ内のすべての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>
2
Kusalananda