Dam*_*ien 8 java xml xslt unicode xml-serialization
我正在尝试使用补充的unicode字符序列化DOM文档,例如U + 1D49C(?,数学脚本大写A).创建具有这样一个字符的节点不是问题(我只是将节点值设置为UTF-16等价物,"\ uD835\uDC9C").但是,在序列化时,Xalan和XSLTC(使用Transformer)和Xerces(使用LSSerializer)都会创建无效的字符实体,例如"" 而不是"𝒜".我尝试了LSSerializer的"normalize-characters"参数,但不支持它.当编码为unicode时,只有Saxon才能正确使用,而不使用字符实体.
我不能在实践中使用Saxon(除了其他原因,我使用Java applet并且不想加载另一个jar),所以我正在寻找一个使用默认JDK库的解决方案.是否可以从具有补充unicode字符的DOM文档中获取有效的XML文档?
[编辑]我发现其他人遇到了这个问题:http://www.dragishak.com/?p = 131
[edit2]实际上,当我在类路径上没有xerces时,似乎可以使用LSSerializer(使用的类是com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl).它不适用于变压器和com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.
由于我没有看到任何答案,而且其他人似乎也有同样的问题,所以我进一步研究了......
为了找到错误的根源,我使用了serializer中的源代码Xalan 2.7.1,该代码也用于Xerces.
org.apache.xml.serializer.dom3.LSSerializerImpl使用org.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可以与 a 一起使用Transformer)在字符方法中做得更好,但它只处理纯文本并忽略所有标记;人们会认为 XML 文件是文本,但由于某种原因ToXMLStream没有扩展ToTextStream)。
org.apache.xalan.transformer.TransformerIdentityImpl也在使用org.apache.xml.serializer.ToXMLStream(由 返回org.apache.xml.serializer.SerializerFactory.getSerializer(Properties format)),因此它遇到了相同的错误。
ToStream用于org.apache.xml.serializer.CharInfo检查某个字符是否应替换为 a String,因此该错误也可以在那里修复,而不是直接在ToStream. CharInfo正在使用带有字符实体列表的属性文件org.apache.xml.serializer.XMLEntities.properties,因此更改此文件也可能是修复该错误的一种方法,尽管到目前为止它只是针对特殊 XML 字符(quot, amp, lt, gt)而设计的。使用与包中的属性文件不同的属性文件的唯一方法ToXMLStream是org.apache.xml.serializer.XMLEntities.properties在类路径之前添加一个文件,这不会很干净......
对于默认的 JDK(1.6 和 1.7),TransformerFactory返回 a com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl,它使用com.sun.org.apache.xml.internal.serializer.ToXMLStream. 在com.sun.org.apache.xml.internal.serializer.ToStream,characters()有时调用processDirty(), 调用accumDefaultEscape(), 可以更好地处理 unicode 字符,但实际上它似乎不起作用(也许processDirty不调用 unicode 字符)...
com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl正在使用com.sun.org.apache.xml.internal.serialize.XMLSerializer,它支持unicode。奇怪的是,XMLSerializer 来自,但在类路径上的when或areXerces并没有使用它。这是因为在可用时使用is 而不是. 在类路径上,使用。警告:并且两者都在清单中引用,因此如果它位于同一目录中并且或位于类路径上,则最终会出现在类路径上!如果只有和位于类路径上,则用作和 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.ToStream在 JDK 内重命名)中。正确处理 unicode 字符的序列化程序是org.apache.xml.serialize.DOMSerializerImpl(com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl在 JDK 内重命名)。然而,Apache 更喜欢ToStream而不是DOMSerializerImpl当它可用时,所以也许它对于其他事情表现得更好(或者也许它只是一个重组)。最重要的是,他们甚至弃用DOMSerializerImpl了Xerces 2.9.0. 因此,以下解决方法可能会产生副作用:
当Xerces和 Apacheserializer位于类路径上时,将“ (doc.getImplementation()).createLSSerializer()”替换为“ new org.apache.xerces.dom.DOMSerializerImpl()”
当 Apacheserializer位于类路径上(例如因为xalan)但不在类路径上时Xerces,请尝试将“ (doc.getImplementation()).createLSSerializer()”替换为“new com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl()”(需要回退,因为此类将来可能会消失)
这两种解决方法会在编译时产生警告。
我没有解决方法XSLT transforms,但这超出了问题的范围。我猜想可以转换为另一个 DOM 文档并用于DOMSerializerImpl序列化。
其他一些解决方法,对于某些人来说可能是更好的解决方案:
Saxon与使用Transformer
使用带UTF-16编码的 XML 文档