XML のエスケープについて

XML では <、>、& 等々が &lt;&gt;&amp; 等々にエスケープされますが、このあたりについてちょっと仕様書のぞいてみました。

以下あたりに書いてる感じでした。

・Extensible Markup Language (XML) 1.0 (Fourth Edition)
- 2.4 Character Data and Markup
http://www.w3.org/TR/2006/REC-xml-20060816/#syntax

Text consists of intermingled character data and markup. [Definition: Markup takes the form of start-tags, end-tags, empty-element tags, entity references, character references, comments, CDATA section delimiters, document type declarations, processing instructions, XML declarations, text declarations, and any white space that is at the top level of the document entity (that is, outside the document element and not inside any other markup).]


[Definition: All text that is not markup constitutes the character data of the document.]


The ampersand character (&) and the left angle bracket (<) must not appear in their literal form, except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section. If they are needed elsewhere, they must be escaped using either numeric character references or the strings "&amp;" and "&lt;" respectively. The right angle bracket (>) may be represented using the string "&gt;", and must, for compatibility, be escaped using either "&gt;" or a character reference when it appears in the string "]]>" in content, when that string is not marking the end of a CDATA section.


( 略 )


To allow attribute values to contain both single and double quotes, the apostrophe or single-quote character (') may be represented as "&apos;", and the double-quote character (") as "&quot;".

稚拙ながら少し日本語訳を。

テキストはキャラクタデータとマークアップからなる。[ マークアップとは、開始タグ <、終了タグ > ... ( 略 ) ... のこと ]


[ マークアップ以外のすべてのテキストはドキュメントの character data を構成する ]


& と < はリテラルフォーム内に現れてはならない。マークアップのデリミタ、コメント、処理命令?( とかのことですかね )、CDATA セクションを除いては。もし、マークアップのデリミタ等以外の場所で &、< なりが必要な場合、数値文字参照、もしくは、"&amp;"、"&lt;" にそれぞれエスケープされなければならない。> は "&gt;" に置き換えられるかもしれない。互換性のために ( SGML との話っぽい )、コンテンツ内に "]]>" が出てきて、その文字列が CDATA の終わりを示すわけではない時は、"&gt;" か数値文字参照を使ってエスケープされなければならない。


属性の値に '、" を含めるのと許すために、' は "&apos;"、" は "&quot;" に置き換えられるかもしれない。

かなり怪しい部分はありますが、上記踏まえると、仕様的にエスケープしなければならないのは &、<、あと場合によって > だけなんですね。"、' については属性の値として使う場合について言及あるものの、その他の箇所での使用については言及されてない感じですね。まぁ、仕様書を部分的にしか確認してないので、他の箇所以外に書いてあるかもですが、内容的にここに書いてなければ書いてなさそうかなぁとか思います。


Java での動作を以下のコードでちょっと確認してみました。

■ CreateXML.java

package xml;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class CreateXML {
  public static void main(String args[]) throws Exception {
    String date = "[&<>\"']";

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.newDocument();

    Element root = document.createElement("root");
    document.appendChild(root);

    Element e1 = document.createElement("e1");
    root.appendChild(e1);
    e1.setAttribute("a1", date);
    e1.appendChild(document.createTextNode(date));

    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    DOMSource source = new DOMSource(document);
    StreamResult result = new StreamResult(System.out);

    transformer.transform(source, result);
  }
}

■ 動作結果

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<e1 a1="[&amp;&lt;&gt;&quot;']">[&amp;&lt;&gt;"']</e1>
</root>

属性の値、仕様書で言うところのキャラクタデータに [&<>"'] を設定してみました。「&、<、> についてはどちらの場合もエスケープされる」、「" は属性の値の場合にエスケープされてキャラクタデータではエスケープされず」、「' はどちらでもエスケープされず」という感じの実装に Java はなっているみたいですね。


以上になります。

[ 環境情報 ]
Windows 7 SP1
Java SE 8 Update 25