Могу ли я применить порядок атрибутов XML, используя схему?

Наше приложение C++ считывает данные конфигурации из файлов XML, которые выглядят примерно так:

<data>
 <value id="FOO1" name="foo1" size="10" description="the foo" ... />
 <value id="FOO2" name="foo2" size="10" description="the other foo" ... />
 ...
 <value id="FOO300" name="foo300" size="10" description="the last foo" ... />
</data>

Полная конфигурация приложения состоит из ~2500 этих XML-файлов (что составляет более 1,5 миллиона пар ключ / значение). Файлы XML поступают из разных источников / команд и проверяются на соответствие схеме. Однако иногда <value/> узлы выглядят так:

<value name="bar1" id="BAR1" description="the bar" size="20" ... />

или это:

<value id="BAT1" description="the bat" name="bat1"  size="25" ... />

Чтобы ускорить этот процесс, мы используем Expat для анализа XML-документов. Expat предоставляет атрибуты в виде массива, например:

void ExpatParser::StartElement(const XML_Char* name, const XML_Char** atts)
{
 // The attributes are stored in an array of XML_Char* where:
 //  the nth element is the 'key'
 //  the n+1 element is the value
 //  the final element is NULL
 for (int i = 0; atts[i]; i += 2) 
 {
  std::string key = atts[i];
  std::string value = atts[i + 1];
  ProcessAttribute (key, value);
 }
}

Это возлагает всю ответственность на наших ProcessAttribute() Функция, чтобы прочитать "ключ" и решить, что делать со значением. Профилирование приложения показало, что ~40% общего времени синтаксического анализа XML связано с этими атрибутами по имени / строке.

Весь процесс мог бы быть значительно ускорен, если бы я мог гарантировать / обеспечить порядок атрибутов (для начала, нет сравнения строк в ProcessAttribute()). Например, если атрибут 'id' всегда был первым атрибутом, мы могли бы иметь дело с ним напрямую:

void ExpatParser::StartElement(const XML_Char* name, const XML_Char** atts)
{
 // The attributes are stored in an array of XML_Char* where:
 //  the nth element is the 'key'
 //  the n+1 element is the value
 //  the final element is NULL
 ProcessID (atts[1]);
 ProcessName (atts[3]);
 //etc.
}

В соответствии со спецификациями схемы W3C, я могу использовать <xs:sequence> в XML-схеме для обеспечения порядка элементов - но это не работает для атрибутов - или, возможно, я использую его неправильно:

<xs:element name="data">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="value" type="value_type" minOccurs="1" maxOccurs="unbounded" />
  </xs:sequence>
 </xs:complexType>
</xs:element>

<xs:complexType name="value_type">
 <!-- This doesn't work -->
 <xs:sequence>
  <xs:attribute name="id" type="xs:string" />
  <xs:attribute name="name" type="xs:string" />
  <xs:attribute name="description" type="xs:string" />
 </xs:sequence>
</xs:complexType>

Есть ли способ обеспечить порядок атрибутов в документе XML? Если ответ "нет", может кто-нибудь предложить альтернативу, которая не будет иметь огромных потерь производительности во время выполнения?

8 ответов

Решение

Согласно спецификации XML,

порядок определения атрибутов в теге start-tag или empty-element не имеет значения

Вы можете проверить это в разделе 3.1

У атрибутов XML нет порядка, поэтому нет порядка для его применения.

Если вы хотите что-то заказать, вам нужны элементы XML. Или что-то отличное от XML. Например, JSON, YAML и bEncode имеют карты (неупорядоченные) и последовательности (упорядоченные).

Как уже отмечали другие, нет, вы не можете полагаться на порядок атрибутов.

Если бы у меня был какой-либо процесс, включающий 2500 файлов XML и 1,5 миллиона пар ключ / значение, я бы вывел эти данные из XML в более удобную форму, как только смог. База данных, двоичный формат сериализации, что угодно. Вы не получаете никаких преимуществ от использования XML (кроме проверки схемы). Я обновлял свой магазин каждый раз, когда получал новый XML-файл, и извлекал 1,5 миллиона XML-элементов из основного потока моего процесса.

Ответ - нет, увы. Я в шоке от вашей цифры 40%. Мне трудно поверить, что превращение "foo" в ProcessFoo занимает так много времени. Вы уверены, что 40% не включают время, затраченное на выполнение ProcessFoo?

Можно ли получить доступ к атрибутам по имени, используя эту вещь Expat? Это более традиционный способ доступа к атрибутам. Я не говорю, что это будет быстрее, но, возможно, стоит попробовать.

Я не думаю, что XML-схема поддерживает это - атрибуты просто определены и ограничены по имени, например, они должны соответствовать определенному имени - но я не вижу, как вы могли бы определить порядок для этих атрибутов в XSD.

Я не знаю другого способа убедиться, что атрибуты на узле XML приходят в определенном порядке - не уверен, что какой-либо другой механизм схемы XML, такой как Schematron или Relax NG, поддержит это....

Я почти уверен, что нет способа обеспечить порядок атрибутов в документе XML. Я собираюсь предположить, что вы можете настаивать на этом с помощью бизнес-процесса или других человеческих факторов, таких как контракт или другой документ.

Что если вы просто предположили, что первым атрибутом был "id", и проверили имя, чтобы убедиться? Если да, используйте значение, если нет, то вы можете попытаться получить атрибут по имени или выбросить документ.

Хотя это не так эффективно, как вызов атрибута по порядковому номеру, некоторое ненулевое количество раз вы сможете догадаться, что ваши поставщики данных доставили XML в спецификацию. В остальное время вы можете предпринять другие действия.

Просто предположение, но вы можете попробовать добавить use="required" к каждой из ваших характеристик атрибута?

<xs:complexType name="value_type">
 <!-- This doesn't work -->
 <xs:sequence>
  <xs:attribute name="id" type="xs:string" use="required" />
  <xs:attribute name="name" type="xs:string" use="required" />
  <xs:attribute name="description" type="xs:string" use="required" />
 </xs:sequence>
</xs:complexType>

Мне интересно, замедляется ли синтаксический анализатор, разрешая дополнительные атрибуты, когда он появляется, ваши атрибуты всегда будут там.

Опять просто догадка.

РЕДАКТИРОВАТЬ: спецификация XML 1.0 говорит, что порядок атрибутов не имеет значения. http://www.w3.org/TR/REC-xml/

Таким образом, XSD не будет выполнять любой заказ. Но это не значит, что парсеры не могут быть обмануты, чтобы работать быстро, поэтому я держу опубликованный выше ответ на случай, если он действительно сработает.

Из того, что я помню, Expat - не проверяющий парсер и лучше для него.. так что вы, вероятно, можете отказаться от этой идеи XSD. Зависимость от порядка не является хорошей идеей во многих XML-подходах (XSD подвергся критике по порядку элементов, чертовски много назад в тот день, например, за или против продавцов веб-служб XML в MSFT).

Сделайте свое собственное кодирование и просто расширяйте свою логику для более эффективного поиска или копайтесь в источнике парсера. Общеизвестно наладить инструментарий для эффективной замены кодирования, одновременно защищая от него программных агентов и пользователей. Вы хотите сделать это, чтобы его можно было легко перенести, сохраняя обратную совместимость и обратимость. Кроме того, перейдите к ограничениям фиксированного размера / атрибут-имя-перевод.

[Считай, что тебе повезло с Expat:) и его сырой скоростью. Представьте, как разработчики CLR любят средства масштабирования XML, они регулярно отправляют 200 МБ по проводам в процессе "просто запроса к базе данных".. ]

Другие вопросы по тегам