REXML сохранить порядок атрибутов - PullRequest
3 голосов
/ 22 февраля 2009

Я пытаюсь сгенерировать такой XML, используя REXML

<root>
  <add key='foo' value='bar'/>
</root>

Но что я получаю (обратите внимание, что порядок ключей / значений)

<root>
  <add value='bar' key='foo'/>
</root>

Код:

require 'rexml/document'
include REXML

doc = Document.new
doc.add_element('root')
el = doc.root.add_element('add')
el.add_attribute('key', 'foo')
el.add_attribute('value', 'bar')
puts doc

Неважно, если я напишу:

el.add_attribute('key', 'foo')
el.add_attribute('value', 'bar')

или

el.add_attribute('value', 'bar')
el.add_attribute('key', 'foo')

результат тот же. Похоже, REXML использует некоторый словарь для хранения атрибутов ...

Могу ли я применить желаемый порядок: ключ / значение?

Ответы [ 5 ]

6 голосов
/ 21 октября 2011

Вы можете попробовать использовать специальную REXML::Formatter, не касаясь источников REXML. Сообщение на руби-токе мл предлагает этот код:

class OrderedAttributes < REXML::Formatters::Pretty
    def write_element(elm, out)
        att = elm.attributes

        class <<att
            alias _each_attribute each_attribute

            def each_attribute(&b)
                to_enum(:_each_attribute).sort_by {|x| x.name}.each(&b)
            end
        end

        super(elm, out)
    end
end

fmt = OrderedAttributes.new
fmt.write(doc, $stdout)
6 голосов
/ 22 февраля 2009

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

Из спецификации XML здесь обратите внимание на фразу: «Обратите внимание, что порядок спецификаций атрибутов в начальном теге или теге пустого элемента не имеет значения».

В ответ на ваш конкретный вопрос о том, можете ли вы выполнить определенный приказ, я не верю в это. На самом деле я никогда не пытался это сделать (так как это не нужно), но вряд ли люди из REXML будут тратить время на реализацию подобной функции :-). Поскольку пары ключ / значение хранятся в виде хэша, их порядок, скорее всего, будет случайным (насколько вы можете судить по алфавитной последовательности ключей).

Конечно, поскольку Ruby поставляется с исходным кодом для REXML, вы можете (в случае отчаяния) заменить или дополнить включенную копию своей собственной версией (REXML2?).

Поскольку вы выполняете простые операции размещения, возможно, он использует симпатичный форматтер, поэтому проверьте начало кода write_element в src/rexml/formatters/pretty.rb, где он выполняет "node.attributes.each_attribute do |attr|" - вы можете обнаружить, что это так же просто, как сортировка этот список до обработки элементов.

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

1 голос
/ 20 октября 2013

Упрощенная версия отличного решения Gioele:

Если мы сделаем список атрибутов отсортированным, то вывод будет детерминированным, что является важным фактором во избежание ложных изменений между версиями сгенерированных документов XML.

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

# make REXML sort attributes by name so output is deterministic
module REXML
  class Attributes
    alias _each_attribute each_attribute
    def each_attribute(&b)
      to_enum(:_each_attribute).sort_by {|x| x.name}.each(&b)
    end
  end
end
1 голос
/ 23 февраля 2009

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

Кроме того, имейте в виду, что генерация большого количества XML через REXML невероятно медленная. У меня был сайт, который должен был читать и писать много XML; Я обнаружил, что для чтения REXML был достаточно быстрым, но для записи мне пришлось использовать libxml. И на самом деле, libxml был таким сложным для установки, а библиотеки ruby ​​для него настолько незрелыми, что в итоге я использовал erb, чтобы просто заменить некоторые части уже написанных документов XML.

Удачи!

0 голосов
/ 24 ноября 2012

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

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