Analisando mais de 12.000 arquivos XML

1

Eu tenho uma pasta que contém mais de 12.000 arquivos XML. Preciso obter uma lista de arquivos dentro dessa pasta que atendam a determinados critérios.

No arquivo XML, existe um nó chamado /BillingData/InvoiceLinesList/InvoiceLines . Pode haver um ou mais InvoiceLines dentro do InvoiceLinesList . No InvoiceLines , preciso procurar uma tag chamada <charge> cujo valor seja 99 e também onde exista uma tag no mesmo InvoiceLines chamado <chargeType> , em que o valor é D .

Qual é a melhor maneira de fazer isso? Usando awk , achei que seria possível fazer isso, mas não consegui encontrar uma maneira de pesquisar várias condições, pois não sou grande em awk . Vi um método em potencial usando xmlstarlet , mas ele procura apenas um ou outro valor em uma única tag, em vez de separar valores em mais de uma tag.

    
por snert 21.09.2018 / 11:39

1 resposta

2

Ambos awk e sed são geralmente inadequados para analisar XML (e outros formatos semelhantes, como JSON e YAML, etc.). Para este exemplo de XML, por exemplo, não sabemos qual ordem os nós em InvoiceLines estão armazenados ou se eles são delimitados por novas linhas ou não. O formato XML não se preocupa com essas coisas, mas um script awk ou sed cairia facilmente a menos que cuidados excepcionais fossem tomados para cobrir todos os casos possíveis (incluindo as várias codificações possíveis dos dados), caso em que você faria Teria que escrever um analisador XML de qualquer maneira.

Portanto, usar um analisador de XML, como o construído em xmlstarlet , é a coisa certa a se fazer.

O comando a seguir deve imprimir o nome do arquivo de entrada se pelo menos um dos nós requeridos for encontrado no arquivo file.xml . Se vários InvoiceLines nós correspondessem, o nome do arquivo seria impresso várias vezes com uma nova linha no meio. Isso significa que, desde o início, desqualificamos nomes de arquivos contendo novas linhas.

xmlstarlet sel \
    -t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
    --inp-name -nl file.xml

A consulta XPATH corresponderia a todos os InvoiceLines que tinham subnós chargeType e charge com os valores especificados. Usar o @charge em vez do charge teria sido testado contra um atributo charge no nó InvoiceLines , a propósito.

Aplicando isso em todos os arquivos XML em um único diretório:

xmlstarlet sel \
    -t -m '/BillingData/InvoiceLinesList/InvoiceLines[chargeType = "D" and charge = "99"]' \
    --inp-name -nl ./*.xml

Se houver muitos arquivos e os itens acima gerarem um erro, você poderá usar xargs :

printf '%s\n' ./*.xml | xargs xmlstarlet -t -m ...

Ou find (também será pesquisado subdiretórios):

find . -type f -name '*.xml' -exec xmlstarlet -t -m ... {} +

canalize o resultado até uniq se quiser tornar a listagem de arquivos única.

Eu usei o seguinte XML para testar o acima:

<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>
    
por 21.09.2018 / 12:08