Técnicas para analisar XML

11

Eu sempre achei o XML um tanto complicado de processar. Não estou falando sobre a implementação de um analisador XML: estou falando sobre o uso de um analisador baseado em fluxo existente, como um analisador SAX, que processa o nó XML por nó.

Sim, é realmente fácil aprender as várias APIs para esses analisadores, mas sempre que olho para o código que processa XML, sempre acho que é um pouco complicado. O problema essencial parece ser que um documento XML é logicamente separado em nós individuais e, no entanto, os tipos e atributos de dados geralmente são separados dos dados reais, às vezes por vários níveis de aninhamento. Portanto, ao processar qualquer nó específico individualmente, é necessário manter muito estado extra para determinar onde estamos e o que precisamos fazer em seguida.

Por exemplo, dado um trecho de um documento XML típico:

<book>
  <title>Blah blah</title>
  <author>Blah blah</author>
  <price>15 USD</price>
</book>

... Como determinaria quando encontrei um nó de texto contendo um título de livro? Suponha que tenhamos um analisador XML simples que age como um iterador, fornecendo o próximo nó no documento XML toda vez que chamamos XMLParser.getNextNode(). Eu inevitavelmente me pego escrevendo código da seguinte maneira:

boolean insideBookNode = false;
boolean insideTitleNode = false;

while (!XMLParser.finished())
{
    ....
    XMLNode n = XMLParser.getNextNode();

    if (n.type() == XMLTextNode)
    {
        if (insideBookNode && insideTitleNode)
        {
            // We have a book title, so do something with it
        }
    }
    else
    {
        if (n.type() == XMLStartTag)
        {
            if (n.name().equals("book")) insideBookNode = true
            else if (n.name().equals("title")) insideTitleNode = true;
        }
        else if (n.type() == XMLEndTag)
        {
            if (n.name().equals("book")) insideBookNode = false;
            else if (n.name().equals("title")) insideTitleNode = false;
        }
    }
}

Basicamente, o processamento XML rapidamente se transforma em um enorme loop controlado por máquina de estado, com muitas variáveis ​​de estado usadas para indicar nós-pai que encontramos anteriormente. Caso contrário, um objeto de pilha precisa ser mantido para acompanhar todas as tags aninhadas. Isso rapidamente se torna propenso a erros e difícil de manter.

Novamente, o problema parece ser que os dados em que estamos interessados ​​não estão diretamente associados a um nó individual. Claro, poderia ser, se escrevêssemos o XML como:

<book title="Blah blah" author="blah blah" price="15 USD" />

... mas raramente é assim que o XML é usado na realidade. Principalmente, temos nós de texto como filhos dos nós pais e precisamos acompanhar os nós pais para determinar a que um nó de texto se refere.

Então ... estou fazendo algo errado? Existe uma maneira melhor? Em que momento o uso de um analisador baseado em fluxo XML se torna muito complicado, para que um analisador DOM completo seja necessário? Eu gostaria de ouvir de outros programadores que tipo de idioma eles usam ao processar XML com analisadores baseados em fluxo. A análise XML baseada em fluxo deve sempre se transformar em uma enorme máquina de estado?

Channel72
fonte
2
Se você estiver usando uma linguagem .net, deve consultar linq to xml, também conhecido como XLinq.
Muad'Dib
Obrigado, eu pensei que era o único com este problema. Francamente, muitas vezes acho que todo o formato XML é mais um obstáculo do que uma ajuda. Sim, permite armazenar muitos dados estruturados em um pequeno arquivo de texto. Mas se você precisar de mais de 20 aulas para descompactar e entender a coisa - sem garantia de que não está negligenciando algo mais ou menos importante. É como o coelho no Santo Graal de Monty Python.
Elise van Looij

Respostas:

9

Para mim, a questão é o contrário. Em que momento um documento XML se torna tão complicado que você precisa começar a usar o SAX em vez do DOM?

Eu usaria apenas o SAX para um fluxo de dados muito grande e de tamanho indeterminado; ou se o comportamento que o XML pretende invocar for realmente orientado a eventos e, portanto, semelhante ao SAX.

O exemplo que você dá parece muito com o DOM para mim.

  1. Carregar o XML
  2. Extraia o (s) nó (s) do título e "faça algo com eles".

Edição: Eu também usaria SAX para fluxos que podem estar malformados, mas onde eu quero fazer um palpite para obter os dados.

Paul Butcher
fonte
2
Eu acho que esse é um bom ponto. Se você está analisando documentos que são grandes demais para DOM, em seguida, você precisa considerar se você está documentos de análise que são grandes demais para XML
Dean Harding
1
+1: dada a opção, eu sempre usaria o DOM. Infelizmente, parece que nossos requisitos de design sempre incluem "capacidade de lidar com documentos de qualquer tamanho" e "devem ter desempenho", o que praticamente exclui as soluções baseadas em DOM.
TMN
3
@TMN, em um mundo ideal, os requisitos descartariam o XML em primeiro lugar.
SK-logic
1
@TMN, isso soa como um desses requisitos fantasmas: "É claro que todos os nossos documentos têm apenas cerca de 100 KB e o maior que vimos é de 1 MB, mas você nunca sabe o que o futuro nos reserva, por isso devemos manter nossas opções em aberto. e compilação de documentos infinitamente grandes"
Paul Butcher
@ Paul Butcher, você nunca sabe. Quero dizer, um despejo da Wikipedia é como 30 GB de XML.
precisa saber é o seguinte
7

Eu não trabalho muito com XML, mas na minha opinião, provavelmente uma das melhores maneiras de analisar XML com uma biblioteca é usar XPath.

Em vez de percorrer a árvore para encontrar algum nó específico, você fornece um caminho para ele. No caso do seu exemplo (em pseudocódigo), seria algo como:

books = parent.xpath ("/ book") // Isso forneceria todos os nós do livro
para cada livro em livros
    title = book.xpath ("/ title / text ()")
    author = book.xpath ("/ author / text ()")
    price = book.xpath ("/ price / text ()")

    // Faça coisas com os dados

O XPath é muito mais poderoso que isso, você pode pesquisar usando condições (tanto em valores quanto em atributos), selecionar um nó específico em uma lista, mover níveis pela árvore. Eu recomendo que você procure informações sobre como usá-lo, ele é implementado em várias bibliotecas de análise (eu uso a versão do .NET Framework e o lxml para Python)

Ioachim
fonte
Tudo bem se você puder conhecer e confiar com antecedência na maneira como o xml está estruturado. Se você não souber se, digamos, a largura de um elemento será especificada como um atributo de um nó ou como um nó de atributo dentro do nó de tamanho de um elemento, o XPath não será de grande ajuda.
Elise van Looij
5

A análise XML baseada em fluxo deve sempre se transformar em uma enorme máquina de estado?

Normalmente, sim.

Para mim, apontar para usar um analisador DOM completo é quando eu precisaria imitar partes da hierarquia de arquivos na memória, por exemplo, para poder resolver referências cruzadas no documento.

Alexander Gessler
fonte
+1: comece com DOM. Evite SAX.
S.Lott
ou com vtd-xml
vtd-xml-author 20/10/16
4

A análise em geral é simplesmente dirigir uma máquina de estado, e a análise XML não é diferente. A análise baseada em fluxo é sempre um aborrecimento, eu sempre acabo construindo uma pilha de algum tipo para rastrear os nós ancestrais e definindo muitos eventos e algum tipo de expedidor de eventos que verifica um registro de marca ou caminho e dispara um evento se alguém corresponder. O código principal é bastante restrito, mas acabo com uma enorme quantidade de manipuladores de eventos que consistem principalmente na atribuição do valor do seguinte nó de texto a um campo em uma estrutura em algum lugar. Pode ficar bem peludo se você precisar misturar a lógica de negócios também.

Eu sempre usaria o DOM, a menos que problemas de tamanho ou desempenho determinassem o contrário.

TMN
fonte
1

Não é totalmente independente da linguagem, mas normalmente deserializo o XML em objetos, em vez de pensar em analisar. O único momento para se preocupar com as estratégias de análise em si é se você tiver um problema de velocidade.

Wyatt Barnett
fonte
Isso é analisado. A menos que o XML em questão seja a saída da serialização de objetos e você tenha uma biblioteca de desserialização pronta para uso. Mas então essa pergunta não aparece.
Muitos idiomas / pilhas possuem bibliotecas de desserialização prontas.
Wyatt Barnett
Sim e daí? Meus pontos ainda são válidos - nem todos os arquivos XML em estado selvagem vêm em um formato desse tipo; se você tiver um, você não fará essa pergunta, basta usar a biblioteca de desserialização e não analisar nada por conta própria, de fluxos ou de outra forma.
0

Torna-se muito menos complicado se você pode usar o XPath. E no .Net land o LINQ to XML abstrai muitas das coisas menos glamourosas também. ( Editar - isso requer uma abordagem DOM, é claro)

Fundamentalmente, se você estiver adotando uma abordagem baseada em fluxo (para que você não possa usar abstrações mais agradáveis ​​que exijam um DOM), acho que sempre será bastante complicado e não tenho certeza de que haja alguma maneira de contornar isso.

Steve
fonte
Se você estiver usando o XPath, está usando o DOM (a menos que esteja usando um avaliador XPath doméstico).
TMN
sim, daí meu comentário sobre as abstrações que exigem DOM ... mas vou esclarecer, obrigado!
8113 Steve
0

Se você puder encontrar um analisador que fornece um iterador, você pensou em tratá-lo como um lexer e usar um gerador de máquina de estado?

Demi
fonte