Xpath für XML als String unter Java - StringyXmlReader
Wednesday, 16. February 2011
Der StringyXmlParser ist von mir. Er versteht XML als String, iteriert dort drüber, um schließlich einen String oder einen Vektor von Strings zurückzugeben.
Bevor ich das weiter erkläre sollte ich die Vorgeschichte erzählen, bevor mir hierfür später mal der Kopf abgerissen wird. Eine Api gab XML zurück und das musst geparst werden. Also schaute ich mir an, was es dafür unter Java so alles gibt. Zuerst fand ich SAX, und auch wenn das inzwischen alles seinen Sinn hat: Die impliziten Funktionsaufrufen bei den Events habe ich damals schlichtweg nicht verstanden.
Dann versuchte ich, ein DOM-Objekt zu erstellen, und bekam dort immer null zurück, in ähnliche Fehler rannte ich noch bei anderen Wegen. Schießlich wurde mir das zu blöd, die Auflistung der vorhandenen Tools ist doch eine Aufzählung des Elends. Ich suchte noch eine Weile und habe dabei wahrscheinlich eine äußerst einfache Lösung übersehen (nicht vergessen: Ich rannte in Bugs oder machte etwas falsch, sodass solche netten Lösungen nicht funktionierten). Schließlich beschloss ich, mir eben selbst den Komfort zu bauen den es unter Bash schon lange gibt: Ein Tool, das XML als String und einen XPath-Ausdruck frisst und daraufhin einen Wert zurückgibt.
getNode(xml, xpath)
Also zum StringyXmlParser. Die grundsätzliche Benutzung sollte aus folgendem Beispiel klarwerden:
String xml = "<root>" + "<group>" + "<field>" + "abc" + "</field>" + "<field>" + "def" + "</field>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); Vector<String> nodes = sxp.getNode(xml, "/root/group"); for (String node: nodes) { assertTrue(node.equals("<group><field>abc</field><field>def</field></group>")); }
getValue(xml)
Will man nicht einen kompletten Node, sondern den Inhalt eines Nodes:
String xml = "<root id=\"1\" value=\"abc def\" data=\"12dv\" >" + "<group>" + "<field>" + "abc" + "</field>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); String value = sxp.getValue(sxp.getNode(xml, "/root/group/field").get(0)); assertTrue(value.equals("abc"));
getAttribute(xml, id)
Ebenso einfach kommt man an Attribute:
String xml = "<root id=\"1\" value=\"abc def\" data=\"12dv\" >" + "<group>" + "<field />" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); String attribute1 = sxp.getAttribute(xml, "id"); String attribute2 = sxp.getAttribute(xml, "value"); assertTrue(attribute1.equals("1")); assertTrue(attribute2.equals("abc def"));
searchNode(xml, nodeName)
Natürlich gibt es auch die Möglichkeit, einfach nach einem Node zu suchen:
String xml = "<root>" + "<group>" + "<field>" + "abc" + "</field>" + "<field>" + "def" + "</field>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); Vector<String> nodes = sxp.searchNode(xml, "group"); for (String node: nodes) { assertTrue(node.equals("<group><field>abc</field><field>def</field></group>")); }
searchComplex(xml, nodeName1, value, nodeName2, rückgabetyp, exakteGleichheit)
Oder auch komplizierter: In der Gruppe, bei der ein Node (field1) einen bestimmten Wert hat (abc), wird der Wert des benachbarten Nodes (field2) zurückgegeben (oder der ganze Node, wenn rückgabeytp false ist). Das brauchte ich oft:
String xml = "<root>" + "<group>" + "<field1>" + "abc" + "</field1>" + "<field2>" + "def" + "</field2>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); String value = sxp.searchComplex(xml, "field1", "abc", "field2", true, false).get(0); assertTrue(value.equals("def"));
Abschlussworte
Ist das nun die Erleuchtung, der definitive Weg um mit XML-Dateien umzugehen? Eher nicht. Ich benutze den Parser, um sowohl HTML als auch XML auszulesen, z.B. nutzt der Blogzähler ihn um auf den Blogs nach Faktoren für eine bestimme Blogplattform zu suchen. Das funktioniert ziemlich gut, also: Dort funktioniert sxp ziemlich gut. Doch wenn man in den Code schaut wird man feststellen, dass er keineswegs garantiert funktionieren wird - er betrachtet XML eben als String und geht dementsprechend dort durch. Das kann scheitern (stringy bedeutet nicht umsonst auch zäh). Dagegen finde ich es aber äußerst interessant und vermisste das früher oft, dass sxp einen Node einfach wieder als XML frisst und man darauf direkt wieder einen Xpath-Ausdruck anwenden kann. Das ist der Vorteil, wenn man syntaktische Korrektheit schlichtweg ignoriert.
An sich ist die Benutzung des StringyXmlParsers ein angenehmer und sehr einfacher Weg, mit XML umzugehen. Ich bin recht sicher, dass ich ihn noch eine Weile als eines meiner Standardwerkzeuge unter Java benutzen werde, solange ich nicht in unheilbare Bugs oder gravierende Performance-Probleme renne (die sich bisher nicht abzeichneten). Nebenbei: Lizenz ist die GPL.
Download: StringyXmlParser-0.1.tar.gz
onli blogging am : JTidy
Vorschau anzeigen
onli blogging am : Eigene XML-Parser
Vorschau anzeigen