Я пытаюсь выяснить, что должно произойти, когда синтаксический анализатор XML читает атрибут a
элемента x
в примере ниже:
<!DOCTYPE x [
<!ELEMENT x EMPTY>
<!ATTLIST x a CDATA #IMPLIED>
<!ENTITY d "
">
<!ENTITY a "
">
<!ENTITY t "	">
<!ENTITY t2 " "><!-- a real tab-->
]>
<x a="CARRIAGE_RETURNS:(&d;
),NEWLINES:(&a;
),TABS:(&t;	&t2; )"/><!-- a real tab at the end -->
Существенная часть нормализации значений атрибутов в спецификации включает в себя обход значения атрибута и применение этого оператора case:
- Для ссылки на символ добавьте ссылочный символ к нормализованному значению.
- Для ссылки на сущность, рекурсивно примените шаг 3 [это описание случая] этого алгоритма к тексту замены сущности. [EDIT: текст замены , в отличие от буквального значения сущности , кажется ключевым понятием в понимании того, что происходит. См. Ниже.]
- Для символа пробела (# x20, #xD, #xA, # x9) добавьте символ пробела (# x20) к нормализованному значению.
- Для другого символа добавьте символ к нормализованному значению.
Мое чтение этих правил привело бы меня к мысли, что вывод синтаксического анализатора XML для значения атрибута должен быть следующим (интерпретация: те же правила применяются независимо от того, сохраняются ли ссылки на атрибуты или сущности - символы, заменяются фактические символы):
* 1 028 * CARRIAGE_RETURNS: ([CR] [CR]), Newlines: ([NL] [NL]), ВКЛАДКИ: ([TAB] [TAB] [SPACE] [SPACE]) * * тысяча двадцать-девять
Тем не менее, пример, приведенный чуть ниже того, что в спецификации предполагает, что вывод должен быть следующим, и тест Java, который я написал, работает именно таким образом (интерпретация: если это значение сущности, то оно всегда замена):
CARRIAGE_RETURNS: ([SPACE] [CR]), Newlines: ([SPACE] [NL]), ВКЛАДКИ: ([SPACE] [TAB] [SPACE] [SPACE]) * 1 037 *
С другой стороны, тест, который я написал в PHP, выводит это (интерпретация: если это значение сущности, это никогда замена):
* * CARRIAGE_RETURNS тысячи сорок четыре: ([CR] [CR]), Newlines: ([NL] [NL]), ВКЛАДКИ: ([TAB] [TAB] [TAB] [SPACE]) * * тысяча сорок-пять
Аналогичный вывод получается при запуске xml-файла через XSLT-преобразование с использованием инструмента xsltproc:
<x a="CARRIAGE_RETURNS:( ),NEWLINES:( ),TABS:(			 )"/>
Итак, мой вопрос: что должно произойти и почему?
Ниже приведены примеры программ на PHP и Java:
PHP:
// Library versions from phpinfo():
// DOM/XML API Version 20031129
// libxml Version 2.6.32
$doc = new DOMDocument();
$doc->load("t.xml");
echo str_replace(array("\t", " ", "\r", "\n"), array("[TAB]", "[SPACE]", "[CR]", "[NL]"), $doc->documentElement->getAttribute("a")), "\n";
Java:
import java.io.*;
class T{
public static void main(String[] args) throws Exception {
String xmlString = readFile(args[0]);
System.out.println(xmlString);
org.w3c.dom.Document doc =
javax.xml.parsers.DocumentBuilderFactory.newInstance().
newDocumentBuilder().
parse(new org.xml.sax.InputSource(new StringReader(xmlString)));
System.out.println(doc.getImplementation());
System.out.println(
doc.
getDocumentElement().
getAttribute("a").
replace("\t", "[TAB]").
replace(" ", "[SPACE]").
replace("\r", "[CR]").
replace("\n", "[NL]")
);
}
// Very rough, but works in this case
private static String readFile(String fileName) throws IOException {
File file = new File(fileName);
InputStream inputStream = new FileInputStream(file);
byte[] buffer = new byte[(int)file.length()];
int length = inputStream.read(buffer);
String result = new String(buffer, 0, length);
inputStream.close();
return result;
}
}