Zawsze uważałem, że XML jest nieco kłopotliwy w przetwarzaniu. Nie mówię o implementacji analizatora składni XML: mówię o używaniu istniejącego analizatora opartego na strumieniu, takiego jak analizator składni SAX, który przetwarza węzeł XML według węzła.
Tak, naprawdę łatwo jest nauczyć się różnych interfejsów API dla tych parserów, ale kiedy patrzę na kod przetwarzający XML, zawsze uważam, że jest nieco skomplikowany. Zasadniczym problemem wydaje się być to, że dokument XML jest logicznie podzielony na poszczególne węzły, a jednak typy danych i atrybuty są często oddzielone od rzeczywistych danych, czasami przez wiele poziomów zagnieżdżenia. Dlatego podczas indywidualnego przetwarzania dowolnego węzła należy zachować wiele dodatkowych stanów, aby określić, gdzie jesteśmy i co musimy zrobić dalej.
Na przykład biorąc fragment kodu z typowego dokumentu XML:
<book>
<title>Blah blah</title>
<author>Blah blah</author>
<price>15 USD</price>
</book>
... Jak określić, kiedy napotkałem węzeł tekstowy zawierający tytuł książki? Załóżmy, że mamy prosty parser XML, który działa jak iterator, dając nam następny węzeł w dokumencie XML za każdym razem, gdy wywołujemy XMLParser.getNextNode()
. Nieuchronnie piszę następujący kod:
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;
}
}
}
Zasadniczo przetwarzanie XML szybko zmienia się w ogromną pętlę sterowaną maszyną stanu, z dużą ilością zmiennych stanu używanych do wskazywania węzłów nadrzędnych, które znaleźliśmy wcześniej. W przeciwnym razie należy zachować obiekt stosu, aby śledzić wszystkie zagnieżdżone znaczniki. Szybko staje się to podatne na błędy i trudne do utrzymania.
Ponownie wydaje się, że problemem jest to, że dane, którymi jesteśmy zainteresowani, nie są bezpośrednio powiązane z pojedynczym węzłem. Jasne, może tak być, gdybyśmy napisali XML w następujący sposób:
<book title="Blah blah" author="blah blah" price="15 USD" />
... ale tak rzadko używa się XML w rzeczywistości. Przeważnie mamy węzły tekstowe jako dzieci węzłów nadrzędnych i musimy śledzić węzły nadrzędne, aby ustalić, do czego odnosi się węzeł tekstowy.
Więc ... robię coś złego? Czy jest lepszy sposób? W którym momencie użycie parsera opartego na strumieniu XML staje się zbyt skomplikowane, więc niezbędny jest w pełni parser DOM? Chciałbym usłyszeć od innych programistów, jakiego rodzaju idiomów używają podczas przetwarzania XML z analizatorami strumieniowymi. Czy parsowanie strumieniowe XML musi zawsze zamieniać się w wielką maszynę stanów?