4

私の XSLT 変換は、Unicode 文字 (おそらく絵文字) を含む XML ファイルに出くわすまで、数か月間成功していました。Unicode を保持する必要がありますが、XSLT はそれを HTML エンティティに変換しています。エンコーディングを UTF-8 に設定すると問題が解決すると思っていましたが、まだ問題が発生しています。

どんな助けでも感謝します。コード:

private byte[] transform(InputStream stream) throws Exception{
    System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl"); 

    Transformer xmlTransformer;

    xmlTransformer = (TransformerImpl) TransformerFactory.newInstance().newTransformer(new   StreamSource(createXsltStylesheet()));
    xmlTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

    XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(stream,"UTF-8");
    Source staxSource = new StAXSource(reader, true); 
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
    xmlTransformer.transform(staxSource, new StreamResult(writer));


    return outputStream.toByteArray();
}

追加すると

xmlTransformer.setOutputProperty(OutputKeys.METHOD, "text");

Unicode は保持されますが、XML は保持されません。

4

4 に答える 4

1

私はちょうどこの同じ問題に出くわしました. あまりにも長い間調査した後、これが私が結論付けたことです.

Java XSLT プロセッサは、出力モードが XML の場合でも、マルチバイト UTF-8 文字を HTML エンティティにエスケープします...マルチバイト文字が CDATA でラップされていない text() ノードで発生した場合。文字が (出力用に) CDATA でラップされている場合、マルチバイト文字は保持されます。

私の問題:

私は絵文字を完備したこのようなxmlファイルを持っていました。

<events>
    <event>
       <id>RANDOMID</id>
       <blah>
          <blahId>FOOONE</blahId>
       </blah>
       <blah>
          <blahId>FOOTWO</blahId>
       </blah>
       <eventComment>Did some things. Had some Fun. </eventComment>
    </event>
</events>

次のような XSL スタイルシートから始めました。

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/xhtml1/strict"
>
    <xsl:output method = "xml" version="1.0" encoding = "UTF-8" omit-xml-declaration="no" indent="yes" />

    <xsl:template match="/">
        <events>
            <xsl:for-each select="/events/event">
                <event>
                    <xsl:copy-of select="./*[name() != 'blah'"/>
                    <xsl:for-each select="./blah">
                        <blahId><xsl:copy-of select="./blahId/text()"/></blahId>
                    </xsl:for-each>
                </event>
            </xsl:for-each>
        </events>
    </xsl:template>
</xsl:stylesheet>

これをJava Transformerで実行すると&#55357;&#56397;、絵文字があるべき場所に一貫して生成されました。結果のドキュメントを解析する後続の試みは、次の例外メッセージで失敗しました:

org.xml.sax.SAXParseException; lineNumber: y; columnNumber: x; Character reference "&#55357" is an invalid XML character.

ホグウォッシュ!

マルチバイト文字に関しては愚かではないxsltprocため、コマンドラインでこれをテストしても役に立ちませんでした。xsltproc期待どおりの出力が得られました。

解決策

tag属性で QName を指定して XSLTeventCommentで CDATA をラップすると、バイトが保持され、 xsltprocおよび Java Transformerで動作します。xsl:outputcdata-section-elements

ここでの魔法は、タグcdata-secion-elementsからの出力プロパティです。https://www.w3.org/TR/xslt#output<xsl:output>

XSL テンプレートを次のように更新しました。

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/xhtml1/strict"
>
    <xsl:output  cdata-section-elements="eventComment" method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="no" indent="yes"/>

    <xsl:template match="/">
        <events>
            <xsl:for-each select="/events/event">
                <event>
                    <xsl:copy-of select="./*[name() != 'blah' and name() != 'eventComment']"/>
                    <!-- For the cdata-section-elements to resolve that eventComment needs to be preserved as CDATA
                        (so we don't get java doing stupid things with unicode escapment)
                         it needs to be explicitly referenced here.
                    -->
                    <eventComment><xsl:copy-of select="./eventComment/text()"/></eventComment>
                    <xsl:for-each select="./blah">
                        <blahId><xsl:copy-of select="./blahId/text()"/></blahId>
                    </xsl:for-each>
                </event>
            </xsl:for-each>
        </events>
    </xsl:template>
</xsl:stylesheet>

そして、Java Transformer と Java Transformer の両方からの出力はxsltproc次のようになり、Java DocumentBuilders で問題なく解析されます。

<?xml version="1.0" encoding="UTF-8"?>
<events xmlns="http://www.w3.org/TR/xhtml1/strict">
  <event>
    <id xmlns="">RANDOMID</id>
    <eventComment><![CDATA[Did some things. Had some Fun. ]]></eventComment>
    <blahId>FOO</blahId>
    <blahId>FOOTOO</blahId>
  </event>
</events>
于 2016-08-26T20:56:38.373 に答える