Нормализация значения атрибута XML - как обрабатывать пробелы в сущностях? - PullRequest
2 голосов
/ 30 января 2010

Я пытаюсь выяснить, что должно произойти, когда синтаксический анализатор XML читает атрибут a элемента x в примере ниже:

<!DOCTYPE x [
  <!ELEMENT x EMPTY>
  <!ATTLIST x a CDATA #IMPLIED>
  <!ENTITY d "&#xD;">
  <!ENTITY a "&#xA;">
  <!ENTITY t "&#x9;">
  <!ENTITY t2 " "><!-- a real tab-->
]>
<x a="CARRIAGE_RETURNS:(&d;&#xD;),NEWLINES:(&a;&#xA;),TABS:(&t;&#x9;&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:(&#13;&#13;),NEWLINES:(&#10;&#10;),TABS:(&#9;&#9;&#9; )"/>

Итак, мой вопрос: что должно произойти и почему?

Ниже приведены примеры программ на 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;
  }

}

Ответы [ 2 ]

1 голос
/ 05 февраля 2010

Раздел 4.5: Построение текста замены сущности спецификации XML определяет два важных различия.

  • Для каждой сущности существует различие между ее литеральным значением сущности и замещающим текстом , извлеченным из его литерального значения.
  • Существуют различные правила для этого отображения в зависимости от того, является ли это внутренним или внешним объектом.

Внешняя сущность, для наших текущих целей, может рассматриваться как включаемый файл в C или PHP - это файл или другой внешний ресурс, содержимое которого вставляется, а затем обрабатывается. Внутренний объект передается в полезной нагрузке DTD, и для обеспечения возможности переноса произвольных внутренних объектов без смешивания с синтаксисом DTD он передается в экранированной форме, известной как буквальное значение . Чтобы преобразовать буквенное значение сущности в текст замены , применяется следующее правило:

Для внутренней сущности текст замены - это содержание сущность, после замены персонажа ссылки и параметр-сущность ссылки.

Итак:

  • Буквальное значение сущности "[TAB]" сопоставляется с текстом замены [TAB]. Я объявляю здесь специальный механизм выхода, где [TAB] означает символ табуляции, так как я не могу ввести вкладку в это текстовое поле и понимаю это - я надеюсь, что это не смущает вещи, а скорее демонстрирует факт Есть веские причины иметь механизмы эвакуации, поэтому важно понять, где они используются и как нечто, что выглядит сложным, можно разложить на разные уровни механизма эвакуации.
  • Буквальное значение сущности "&x9;" также сопоставляется с текстом замены [TAB]. Таким образом, что касается логики нормализации значения атрибута, это вкладка, и она не знает, что она была представлена ​​во внутренней сущности с использованием символьной ссылки. Может показаться, что это излишне или что некоторая информация потеряна, но не на самом деле - механизмы побега позволяют вам избегать всего, в том числе вещей, которые вам не нужны, например, вы можете заменить каждое использование Latin строчная буква в файле HTML на &#x61; и не получает и не теряет информацию.
  • Буквальное значение сущности "&#38;#x9;" сопоставляется с текстом замены &#x9;. Логика нормализации значения атрибута будет интерпретировать это как символьную ссылку для вкладки и нормализует ее значение как вкладку, а не свертывает ее.
  • Буквальное значение сущности "&#38;#38;#x9;" сопоставляется с текстом замены &#38;#x9;
  • И так далее ...

Кажется, что-то вроде ошибки в единичном коде или двойной кодировки, что для того, чтобы [TAB] отображался в значении атрибута, ваша внутренняя сущность должна содержать буквенный текст &#38;#x9;. Впечатление от ошибки двойного кодирования создается тем фактом, что DTD используют тот же механизм экранирования символов, что и XML, но по разным причинам. Если в DTD используется другой механизм экранирования, например, для строки, например, \u0009, то буквальное значение сущности будет содержать символы \ uyyyy-escaped с вкраплениями символов & # xyyyy-escaped, и мы всегда можем сказать, какой механизм escape принадлежал до какого уровня. Во всяком случае, это не так, как это делается, поэтому мы просто должны иметь четкое представление о том, что происходит ... это, например, если вы пишете регулярное выражение для обнаружения обратного слэша, вы должны избежать обратного слэша в регулярном выражении с помощью удвоить его, и если вы используете язык без литералов регулярных выражений, вы должны поместить его в строку с правильными экранированными значениями, чтобы получилось четыре обратные косые черты подряд, что выглядит совершенно неправильно, но это правильно, когда вы думаете о взаимодействие разных уровней escape-механизма (кстати, я изначально пытался записать эти обратные слэши, но чтобы обойти собственный escape-механизм Stackoverflow, мне пришлось бы написать восемь обратных слэшей подряд, и это не было безопасно чтобы написать это)

Вышеприведенное на данный момент мне кажется хорошим объяснением спецификации и реализации Java, как показано в примере кода. Очевидно, что это не согласуется с примером PHP, и я не имею в виду, что есть ошибка - реализация PHP DOM располагается поверх зрелой библиотеки C, с большим количеством опций конфигурации, один или несколько из которых могут быть настроены чтобы получить поведение, которое соответствует образцу Java. Подобные примеры позволяют понять, насколько сложен XML ... упрощенные объяснения, подобные приведенному выше, могут быть полезны, чтобы получить общее представление о том, что происходит в 95% случаев, но другие 5% могут быть очень трудными для понимания. понять и объяснить. Поэтому, если в моем объяснении есть изъян или у вас есть лучшее объяснение, добавьте комментарий или другой ответ, чем педантичнее, тем лучше.

1 голос
/ 30 января 2010

Таким образом, вопрос в том, является ли замещающий текст объекта символом возврата каретки, или это символьный объект, который представляет символ возврата каретки?

И если вы посмотрите на примеры в Приложении D к Рекомендации XML (особенно те, которые описаны как «более сложный пример»), то окажется, что заменяющий текст (в вашем примере) должен быть символом возврата каретки, а не персонаж персонажа. Это означает, что ваш «тест Java» является правильным. По крайней мере, если моя интерпретация приложения верна.

Однако обратите внимание, что Приложение D является ненормативным, что означает, что вам необходимо прочитать основную часть Рекомендации, чтобы узнать действительные правила. Я полагаю, что это раздел 4.4, но этот стол только ранил мою голову.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...