ich habe mehrere xml files. Jetzt soll ich rausfinden in welchen ein spezielles tag mit dem Attribut XY vorkommt. Wie würdet ihr das machen ? Mir liegen die XML Dateien schon als Objekt vor. Hab das mit Jaxb gemarshalt.
Das lässt sich auch mit einem einfachen BufferedReader lösen.
Einfach zeilenweise einlesen und nach dem Tag suchen (und gegebenenfalls die Zeile dann ausgeben, je nachdem was passieren soll, wenn der Tag gefunden wurde).
Wenn du nur einen einzigen Wert aus der XML Datei lesen willst, dann ist ein regulärer Ausdruck die einfachste Lösung.
Aus der ganzen Datei einen einzigen langen String machen und dann per RegEx suchen.
Man sollte auf XML-Daten niemals mit String-Operationen arbeiten, also weder mit regulären Ausdrücken, noch mit Suchfunktionen. Der Grund ist, dass XML keine reguläre Grammatik hat und deshalb mächtiger als reguläre Ausdrücke ist. Beispiel: In XML gibt es die Möglichkeit, Kommentare einzufügen - damit kann ein regulärer Ausdruck nicht umgehen, man müsste sich also erstmal mehrere Ausdrücke basteln, um erstmal kommentierte Bereiche zu erkennen.. und wenn man soweit ist, kann man es auch lieber mit einem SAXParser machen, wie von Attila vorgeschlagen. Hier ist ein Beispiel dafür:
Wenn du nur einen einzigen Wert aus der XML Datei lesen willst, dann ist ein regulärer Ausdruck die einfachste Lösung.
Aus der ganzen Datei einen einzigen langen String machen und dann per RegEx suchen.
Mit anderen Worten, deine Datei ist lediglich um die 100kB gross? Das ist winzig. Wo ist da das Problem?
Du könntest z.B. alle Zeilen zu einem StringBuilder hinzufügen.
Aber wie rme schon erwähnt hat, wird bei der Methode alles durchsucht, auch auskommentierte Bereiche. Allerdings ist das in deinem Fall wahrscheinlich kein Problem.
Das halte ich für keine angemessene Herangehensweise. Gründe:
* neben den Kommentaren gibt es weitere Stolperfallen: Ein Attribut kann mit " oder mit ' angegeben werden, zwischen dem = und dem Attributwert können null bis beliebig viele Leerzeichen oder Zeilenumbrüche stehen.. der reguläre Ausdruck wäre so kompliziert, dass man ihn nach ein paar Wochen nicht mehr versteht.
* der Speicherbedarf liegt in O(n), wobei n die Größe der Datei ist. Bei einem SAX-Parser liegt sie in O(m), wobei m die maximale Verschachtelungstiefe der Tags ist.
* sobald man den Code für noch größere Dateien verwenden will, hat man ein Performance- und Speicher-Problem.
Mit regulären Ausdrücken würde ich in diesem Fall nur arbeiten, wenn du zu 100% garantieren kannst, dass du diese Dateien selbst erzeugst, die Größe in diesem Rahmen bleibt und sich das Format nicht mehr ändert. Dann verwendest du nicht XML, sondern eine Teilsprache davon, die auf viele XML-Funktionen verzichtet.
Diese Aufgabe kann man mit dem Standard-Java-SAX-Parser in weniger als 50 Zeilen lösen. Wenn du möchtest, kann ich dir gern ein Beispiel zeigen.
Du hast natürlich Recht. Reguläre Ausdrücke für XML zu verwenden ist unprofessionell. Aber vielleicht benötigt er ja gar keine professionelle Lösung.
Hier mal die kürzeste Lösung, die mir eingefallen ist.
Java:
staticStringfindAttribute(String fileName,String tag,String attribute){try{String xml =newString(Files.readAllBytes(newFile(fileName).toPath()),"utf8");String regEx ="<\\s*"+ tag +"[^<>]*?\\s"+ attribute +"\\s*=\\s*(\".*?\"|\'.*?\')";Matcher m =Pattern.compile(regEx).matcher(xml);if(m.find()){String atr = m.group(1);return atr.substring(1, atr.length()-1);}elsereturnnull;}catch(Exception e){returnnull;}}
Diese Methode liefert dir das gesuchte Attribut als String zurück.
tag und attribute sind dabei der Name des Tags bzw. Attributes.
.*? bedeutet: beliebig viele Zeichen.
Das ? heisst: so wenig Zeichen wie möglich, das ist notwendig, weil =," und ' ja auch beliebige Zeichen sind und versehentlich übersprungen werden könnten.
[^<>] bedeutet: jedes beliebige Zeichen ausser < oder >
\\s ist ein Leerzeichen, Tab oder Zeilenumbruch
| bedeutet oder
(...) ist eine Capture Gruppe
edit: Mein regulärer Ausdruck war nicht ganz in Ordnung. Hab den Code daher noch mal verändert.
Naja, der "kennt" XML und merkt sich, ob er gerade in einem Kommentar ist. Er geht das Dokument durch und ruft bei jedem Element die Methode startElement auf. Die Methode bekommt die Attribute als Parameter, sodass du da direkt prüfen kannst, ob ein Attribut "name" enthalten ist.
Möchtest du ein richtiges Code-Beispiel für diese Aufgabe oder erstmal selbst probieren?
Der SAXparser ist schön und gut, aber wenn ich die Attribute eines tags will, dann muss ich das mit einem INdex aufrufen. Was aber wenn das Attribut mal statt index 0 an index 1 steht.
String tmp = atts.getValue(0); // jetzt bekomm ich den Wert meines 1. Attributs
Der Index ist dazu da, dass du dir mit getLength() die Anzahl der Attribute holst und dann dadurch mit einer Schleife iteriest, also getValue und getLocalName auf jeden Index aufrufst. Du darfst nicht annehmen, dass der index als Zahl gesehen irgendeine Bedeutung hat, die mit dem Dokument zu tun hat - nur für eine Schleife verwenden.
Wenn der Name des Attributes bekannt ist, kannst du aber direkt so prüfen, ob es vorhanden ist: