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?
fonte
Respostas:
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.
Edição: Eu também usaria SAX para fluxos que podem estar malformados, mas onde eu quero fazer um palpite para obter os dados.
fonte
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:
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)
fonte
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.
fonte
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.
fonte
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.
fonte
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.
fonte
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?
fonte