Serialisierung zusätzlicher Unicode-Zeichen in XML-Dokumente mit Java

8

Ich versuche, DOM-Dokumente mit zusätzlichen Unicode-Zeichen wie U + 1D49C (

Damien 14.08.2012, 12:28
quelle

2 Antworten

1

Da ich keine Antwort kommen sah und andere Leute das selbe Problem zu haben scheinen, habe ich weiter darüber nachgedacht ...

Um den Ursprung des Fehlers zu finden, habe ich den Serializer-Quellcode von Xalan 2.7.1 verwendet, der auch in Xerces verwendet wird.

org.apache.xml.serializer.dom3.LSSerializerImpl verwendet org.apache.xml.serializer.ToXMLStream, wodurch org.apache.xml.serializer.ToStream erweitert wird. ToStream.characters (final char chars [], final int start, final int length) behandelt die Zeichen und unterstützt Unicode-Zeichen nicht korrekt (Anmerkung: org.apache.xml.serializer.ToTextSream (das mit einem Transformer verwendet werden kann) macht einen besseren Job in der Zeichenmethode, aber es verarbeitet nur reinen Text und ignoriert alle Markups, man würde denken, dass XML-Dateien Text sind, aber aus irgendeinem Grund erweitert ToXMLStream ToTextStream nicht.

org.apache.xalan.transformer.TransformerIdentityImpl wird auch mit org.apache.xml.serializer.ToXMLStream (die durch org.apache.xml.serializer.SerializerFactory.getSerializer (Eigenschaften Format) zurückgegeben wird), so dass es von leidet der gleiche Fehler.

ToStream verwendet org.apache.xml.serializer.CharInfo, um zu prüfen, ob ein Zeichen durch einen String ersetzt werden sollte, damit der Fehler auch dort anstatt direkt in ToStream behoben werden kann. CharInfo verwendet eine Property-Datei, org.apache.xml.serializer.XMLEntities.properties, mit einer Liste von Zeichen-Entities, daher könnte das Ändern dieser Datei auch eine Möglichkeit sein, den Bug zu beheben, obwohl er bisher nur für das Special entworfen wurde XML-Zeichen quot amp lt gt. Die einzige Möglichkeit, um ToXMLStream eine andere Eigenschaftendatei als die im Paket verwenden zu lassen, wäre eine Datei org.apache.xml.serializer.XMLEntities.properties vor dem Klassenpfad hinzuzufügen, die nicht sehr sauber wäre ...

Mit dem Standard-JDK (1.6 und 1.7), kehrt TransformerFactory ein com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl, die com.sun.org.apache.xml.internal.serializer verwendet. ToXMLStream. In com.sun.org.apache.xml.internal.serializer.ToStream, Zeichen () wird manchmal ruft processDirty (), die accumDefaultEscape () aufruft, die Unicode-Zeichen umgehen konnte besser, aber in der Praxis scheint es nicht zu funktionieren ( vielleicht wird processDirty nicht für Unicode-Zeichen aufgerufen) ...

com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl verwendet com.sun.org.apache.xml.internal.serialize.XMLSerializer, der Unicode unterstützt. Seltsamerweise stammt der XMLSerializer von Xerces und wird dennoch nicht von Xerces verwendet, wenn sich xalan oder xsltc im Klassenpfad befinden. Dies liegt daran, org.apache.xerces.dom.CoreDOMImplementationImpl.createLSSerializer ist org.apache.xml.serializer.dom3.LSSerializerImpl zu verwenden, wenn es statt org.apache.xerces.dom.DOMSerializerImpl zur Verfügung steht. Mit serializer.jar im Klassenpfad wird org.apache.xml.serializer.dom3.LSSerializerImpl verwendet. Warnung: xalan.jar und xsltc.jar verweisen beide auf serializer.jar im Manifest, so dass serializer.jar auf dem Klassenpfad endet, wenn sie sich im selben Verzeichnis befindet und entweder xalan.jar oder xsltc.jar im Klassenpfad ist! Wenn sich nur xercesImpl.jar und xml-apis.jar im Klassenpfad befinden, wird org.apache.xerces.dom.DOMSerializerImpl als LSSerializer verwendet, und Unicode-Zeichen werden ordnungsgemäß behandelt.

Fazit und Abhilfe: Der Fehler liegt in Apache org.apache.xml.serializer.ToStream Klasse (umbenannt com.sun.org.apache.xml.internal.serializer.ToStream innerhalb des JDK). Ein Serializer, der Unicode-Zeichen richtig verarbeitet, ist org.apache.xml.serialize.DOMSerializerImpl (im JDK umbenannt in com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl). Apache zieht jedoch ToStream statt DOMSerializerImpl vor, wenn es verfügbar ist, also verhält es sich vielleicht besser für andere Dinge (oder vielleicht ist es nur eine Reorganisation). Darüber hinaus gingen sie so weit, DOMSerializerImpl in Xerces 2.9.0 abzulehnen. Daher die folgende Problemumgehung, die Nebenwirkungen haben kann:

  • , wenn Xerces und Apache-Serializer auf dem Classpath ist, ersetzen Sie "(doc.getImplementation ()). CreateLSSerializer ()" durch "neue org.apache.xerces.dom.DOMSerializerImpl ()"

  • Wenn Apache's Serializer im Klassenpfad ist (zum Beispiel wegen xalan) aber nicht Xerces, versuchen Sie "(doc.getImplementation ()). createLSSerializer ()" durch "new com.sun.org.apache" zu ersetzen .xml.internal.serialize.DOMSerializerImpl () "(ein Fallback ist erforderlich, da diese Klasse in Zukunft möglicherweise nicht mehr angezeigt wird)

Diese beiden Problemumgehungen erzeugen beim Kompilieren eine Warnung.

Ich habe keine Problemumgehung für XSLT-Transformationen, aber das geht über den Rahmen der Frage hinaus. Ich denke, man könnte eine Transformation in ein anderes DOM-Dokument durchführen und DOMSerializerImpl zum Serialisieren verwenden.

Einige andere Problemumgehungen, die für einige Leute eine bessere Lösung sein könnten:

  • verwenden Saxon mit einem Transformer

  • verwenden XML-Dokumente mit UTF-16-Codierung

Damien 16.08.2012, 12:36
quelle
1

Hier ist ein Beispiel, das für mich funktioniert hat. Der Code ist in Groovy geschrieben und läuft auf Java 7, das Sie leicht in Java übersetzen können, da ich in diesem Beispiel alle Java-APIs verwendet habe. Wenn Sie ein DOM-Dokument mit zusätzlichen Unicode-Zeichen (Ebene 1) übergeben, erhalten Sie einen String zurück, in dem diese Zeichen ordnungsgemäß serialisiert sind. Zum Beispiel, wenn das Dokument ein Unicode-Skript L hat (siehe Ссылка ), wird es in der zurückgegebenen Zeichenfolge als &#x1d4c1 anstelle von �� serialisiert werden (was Sie mit einem Xalan Transformer erhalten).

%Vor%     
2Aguy 14.05.2014 20:57
quelle