Frage

Ich versuche, ein einzelnes XML-Dokument aus dem Strom zu einem Zeitpunkt, zu lesen, mit dom4j, zu verarbeiten, dann zum nächsten Dokument im Stream fortzuzufahren. Leider dom4j der SAXReader (mit JAXP unter der Decke) hält das Lesen und Drosseln auf das folgende Dokument Element.

Gibt es eine Möglichkeit, die SAXReader zu erhalten lesen, den Strom zu stoppen, sobald sie das Ende des Dokumentelements findet? Gibt es einen besseren Weg, dies zu erreichen?

War es hilfreich?

Lösung

Ich war in der Lage zu bekommen dies mit einiger Gymnastik zu arbeiten einige internen JAXP-Klassen:

  • Erstellen Sie einen benutzerdefinierten Scanner, eine Unterklasse von XMLNSDocumentScannerImpl
    • Erstellen Sie eine benutzerdefinierte Treiber, eine Implementierung von XMLNSDocumentScannerImpl.Driver, innerhalb der benutzerdefinierten Scanner, der end_document zurückgibt, wenn es eine Erklärung oder ein Element sieht. Holen Sie sich das ScannedEntity von fElementScanner.getCurrentEntity (). Wenn das Unternehmen eine PushbackReader hat, drücken Sie die verbleibenden ungelesene Zeichen in der Entity-Puffer auf den Leser zurück.
    • Im Konstruktor ersetzt die fTrailingMiscDriver mit einer Instanz dieses speziellen Treiber.
  • Erstellen Sie eine benutzerdefinierte Konfigurationsklasse, eine Unterklasse von XIncludeAwareParserConfiguration, die mit einer Instanz dieser benutzerdefinierten Scanner in seinem Konstruktor.
  • den Bestand DOCUMENT_SCANNER ersetzt
  • Installieren Sie eine Instanz dieser benutzerdefinierten Konfiguration Klasse, die als „com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration“ Eigenschaft, damit es instanziiert werden, wenn dom4j der SAXReader Klasse versucht, einen JAXP XMLReader zu erstellen.
  • Wenn ein Leser zu dom4j der SAXReader.read () Methode übergibt, eine PushbackReader mit einer Puffergröße wesentlich größer als der aus einem Zeichen Standard liefern. Mindestens 8192 sollte ausreichen, um die Standard-Puffergröße des XMLEntityManager innerhalb JAXP Kopie von Apache2 zu unterstützen.

Dies ist nicht die sauberste Lösung, da es interne JAXP-Klassen beinhaltet Subklassen, aber es funktioniert.

Andere Tipps

Wahrscheinlich wollen Sie nicht mehr als ein Dokument im gleichen Strom haben, zur gleichen Zeit. Ich glaube nicht, dass die SAXReader intelligent genug, um zu stoppen, wenn es bis zum Ende des ersten Dokuments bekommt. Warum ist es notwendig, mehrere Dokumente in dem gleichen Strom wie diese zu haben?

Ich denke, man müßte einen Adapter hinzufügen, etwas, um den Strom zu wickeln und das Ding Rückkehr Ende der Datei hat, wenn es den Anfang des nächsten Dokuments sieht. Soweit ich weiß, wie die Parser geschrieben, bis zum Ende der Datei oder einen Fehler gehen ... und sicherlich ein Fehler sein würde, einen anderen <?xml version="1.0"?> sehen.

Angenommen, Sie sind verantwortlich für die Dokumente in den Strom an erster Stelle platzieren sollte leicht sein, die Dokumente in irgendeiner Weise zu begrenzen. Zum Beispiel:

// Any value that is invalid for an XML character will do.
static final char DOC_TERMINATOR=4;

BOOL addDocumentToStream(BufferedWriter streamOut, char xmlData[])
{
  streamOut.write(xmlData);
  streamOut.write(DOC_TERMINATOR);
}

Wenn dann aus dem Strom in ein Array lesen zu lesen, bis DOC_TERMINATOR angetroffen wird.

char *getNextDocuument(BufferedReader streamIn)
{
  StringBuffer buffer = new StringBuffer();
  int character;

  while (true)
  {
    character = streamIn.read();
    if (character == DOC_TERMINATOR)
      break;

    buffer.append(character);
  }
  return buffer.toString().toCharArray();
}

Seit 4 ist ein ungültiges Zeichen Wert Sie werden außer anzutreffen, wo Sie es explizit hinzufügen. Dadurch können Sie die Dokumente teilen. Jetzt nur wickeln Sie den resuling char-Array für die Eingabe in SAX und Ihre gut zu gehen.

...
  XMLReader xmlReader = XMLReaderFactory.createXMLReader();
...
  while (true)
  {
    char xmlDoc = getNextDocument(streamIn);

    if (xmlDoc.length == 0)
      break;

    InputSource saxInputSource = new InputSource(new CharArrayReader(xmlDoc));
    xmlReader.parse(saxInputSource);
  }
...

Beachten Sie, dass die Schleife endet, sobald ein Dokument der Länge bekommt 0. Dies bedeutet, dass Sie entweder eine zweite DOC_TERMINATOR nach dem letzten Dokument hinzufügen, sollten Sie etwas hinzufügen müssen das Ende des Stroms in GetNextDocument () zu erfassen.

Ich habe dies vor mit einem anderen Leser meiner eigenen Schöpfung durch wrappering die Basis Leser getan, die sehr einfach Parsingfähigkeit hatten. Vorausgesetzt, dass Sie den schließenden Tag für das Dokument kennen, analysiert die Hülle einfach für ein Spiel, z.B. für "". Wenn es erkennt, dass es EOF zurückgibt. Die Umhüllung kann durch Parsing aus dem ersten Starttag und Zurückkehren EOF auf dem passenden Schließ tag adaptiv gemacht werden. Ich fand es nicht notwendig war, um tatsächlich das Niveau für den schliessende Tag zu erkennen, da kein Dokument, das ich innerhalb des Schrift Tag benutzt hatte, so wurde sichergestellt, dass das erste Auftreten des Schluss-Tages das Dokument beendet.

Wie ich mich erinnere, einer der Tricks war der Wrapper Block close () zu haben, da die DOM-Leser den Quelleneingang geschlossen wird.

So, da Reader-Eingang, der Code Macht wie folgt aussehen:

SubdocReader sdr=new SubdocReader(input);
while(!sdr.eof()) {
    sdr.next();
    // read doc here using DOM
    // then process document
    }
input.close();

Die eof () Methode gibt true zurück, wenn EOF angetroffen wird. Die Methode next () kennzeichnet die Leser zu stoppen Rückkehr -1 für read ().

Hoffentlich Punkte, die Sie in einer nützlichen Richtung.

- Kiwi.

Ich würde den Eingangsstrom in einen internen Puffer lesen. In Abhängigkeit von der erwarteten Gesamtstrom Größe würde ich entweder den gesamten Strom lesen und es dann analysieren oder die Grenze zwischen einer xml und den nächsten erkennen (suche

Der einzige wirkliche Unterschied dann einen Strom mit einer xml und einem Strom mit mehreren xmls zwischen der Handhabung ist der Puffer und Split-Logik.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top