12

U+1D49C (

4

2 に答える 2

6

回答が得られず、他の人も同じ問題を抱えているようだったので、さらに調べました...

バグの原因を突き止めるために、 にも使用されている のserializerソース コードをXalan 2.7.1使用しましたXerces

org.apache.xml.serializer.dom3.LSSerializerImplorg.apache.xml.serializer.ToXMLStream拡張する を使用しますorg.apache.xml.serializer.ToStream

ToStream.characters(final char chars[], final int start, final int length)文字を処理し、Unicode 文字を適切にサポートしていません (注: org.apache.xml.serializer.ToTextSream(これは で使用できますTransformer) は、characters メソッドでより適切に機能しますが、プレーン テキストのみを処理し、すべてのマークアップを無視します。XML ファイルはテキストであると考えられます。 、しかし、何らかの理由でToXMLStream拡張されませんToTextStream)。

org.apache.xalan.transformer.TransformerIdentityImplorg.apache.xml.serializer.ToXMLStream( によって返されるorg.apache.xml.serializer.SerializerFactory.getSerializer(Properties format)) を使用しているため、同じバグに悩まされています。

ToStreamorg.apache.xml.serializer.CharInfo、文字を に置き換える必要があるかどうかを確認するために使用してStringいるため、 で直接ではなく、そこでバグを修正することもできますToStream。は、文字エンティティのリストをCharInfo含むプロパティ ファイル を使用しているため、このファイルを変更することでorg.apache.xml.serializer.XMLEntities.propertiesバグを修正することもできます。パッケージ内のものとは異なるプロパティ ファイルを使用する唯一の方法は、クラスパスの前にファイルを追加することですが、これはあまりクリーンではありません...quotampltgtToXMLStreamorg.apache.xml.serializer.XMLEntities.properties

デフォルトの JDK (1.6 および 1.7) では、 を使用する をTransformerFactory返します。では、ユニコード文字をより適切に処理できるを呼び出す が呼び出されることがありますが、実際には機能しないようです (ユニコード文字では呼び出されない可能性があります)...com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImplcom.sun.org.apache.xml.internal.serializer.ToXMLStreamcom.sun.org.apache.xml.internal.serializer.ToStreamcharacters()processDirty()accumDefaultEscape()processDirty

com.sun.org.apache.xml.internal.serialize.DOMSerializerImplcom.sun.org.apache.xml.internal.serialize.XMLSerializerUnicode をサポートするを使用しています。奇妙なことに、XMLSerializer は から来ていますが、クラスパス上にあるときXercesまで使用されていません。これは、の代わりに が利用可能なときにを使用しているためです。クラスパス上で、が使用されます。警告:どちらもマニフェストで参照されるため、同じディレクトリにあり、またはクラスパス上にある場合はクラスパスになります! とのみがクラスパス上にある場合、は として使用され、Unicode 文字は適切に処理されます。Xercesxalanxsltcorg.apache.xerces.dom.CoreDOMImplementationImpl.createLSSerializerorg.apache.xml.serializer.dom3.LSSerializerImplorg.apache.xerces.dom.DOMSerializerImplserializer.jarorg.apache.xml.serializer.dom3.LSSerializerImplxalan.jarxsltc.jarserializer.jarserializer.jarxalan.jarxsltc.jarxercesImpl.jarxml-apis.jarorg.apache.xerces.dom.DOMSerializerImplLSSerializer

結論と回避策: バグは Apache のorg.apache.xml.serializer.ToStreamクラスにあります ( com.sun.org.apache.xml.internal.serializer.ToStreamJDK 内で名前が変更されます)。Unicode 文字を適切に処理するシリアライザーはorg.apache.xml.serialize.DOMSerializerImpl( com.sun.org.apache.xml.internal.serialize.DOMSerializerImplJDK 内で名前が変更されました) です。ただし、Apache は使用可能な場合よりも優先するため、他の場合にはより適切に動作する可能性がありToStreamますDOMSerializerImpl(または、単に再編成されているだけかもしれません)。その上、彼らは で非推奨DOMSerializerImplにまでなりましたXerces 2.9.0。したがって、副作用がある可能性がある次の回避策:

  • Xercesおよび Apacheがクラスパス上にある場合は、" " を " "にserializer置き換えます(doc.getImplementation()).createLSSerializer()new org.apache.xerces.dom.DOMSerializerImpl()

  • Apacheserializerがクラスパス上にある (たとえば が原因でxalan) が ではない場合、" " を "new "Xercesに置き換えてみてください(このクラスは将来消える可能性があるため、フォールバックが必要です)。(doc.getImplementation()).createLSSerializer()com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl()

これら 2 つの回避策は、コンパイル時に警告を生成します。

の回避策はありませんが、XSLT transformsこれは質問の範囲を超えています。別の DOM ドキュメントに変換して、シリアル化に使用できると思いますDOMSerializerImpl

一部の人々にとってはより良い解決策になるかもしれないいくつかの他の回避策:

  • Saxonと一緒に使うTransformer

  • UTF-16エンコーディングで XML ドキュメントを使用する

于 2012-08-16T12:36:45.740 に答える
2

これが私のために働いた例です。コードは Java 7 で実行される Groovy で記述されています。この例ではすべての Java API を使用しているため、簡単に Java に変換できます。補足 (プレーン 1) Unicode 文字を含む DOM ドキュメントを渡すと、それらの文字が適切にシリアル化された文字列が返されます。たとえば、ドキュメントに Unicode スクリプト L ( http://www.fileformat.info/info/unicode/char/1d4c1/index.htmを参照) がある場合、返される文字列&#x1d4c1では��(これはXalan Transformer で得られるもの)。

import org.w3c.dom.Document
...

def String writeToStringLS( Document doc ) {
  def domImpl = doc.getImplementation()
  def implLS = domImpl.getFeature("LS", "3.0")
  def lsOutput = implLS.createLSOutput()
  lsOutput.encoding = "UTF-8"
  def bo = new ByteArrayOutputStream()
  def out = new BufferedWriter( new OutputStreamWriter( bo, "UTF-8") )
  lsOutput.characterStream = out
  def lsWriter = implLS.createLSSerializer()
  def result = lsWriter.write(doc, lsOutput)
  return bo.toString()
}
于 2014-05-14T20:57:14.227 に答える