Сохранение объявления DOCTYPE с помощью REXML - PullRequest
0 голосов
/ 02 ноября 2011

Я пытаюсь проанализировать файл log4j.xml, отредактировать некоторые атрибуты и записать его обратно.

log4j.xml имеет объявление <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">, но когда я записываю его обратно, объявление меняется на <!DOCTYPE log4j>.

Я открыл файл для разбора с помощью xmlDoc = Document.new(File.new(file, 'r')) и написал с помощью xmlDoc.write(File.new(file, 'w'), 0).

Я также пытался открыть с помощью xmlDoc = Document.new(File.new(file, 'r'), { :raw => :all }).

Есть ли способ сохранить исходное объявление DOCTYPE?

Большое спасибо!

1 Ответ

0 голосов
/ 02 ноября 2011

Боюсь, что это невозможно при использовании rexml. Посмотрите на это краткое резюме - это «облегченная версия» процесса, который происходит в rexml library

require 'rexml/source'

LETTER = '[:alpha:]'
COMBININGCHAR = ''
EXTENDER = ''
NCNAME_STR= "[#{LETTER}_:][-[:alnum:]._:#{COMBININGCHAR}#{EXTENDER}]*"

IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um

string = <<HERE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration>
</log4j:configuration>
HERE
source = REXML::SourceFactory.create_from(string)
md = source.match( DOCTYPE_PATTERN, true )
identity = md[1]
close = md[2]
identity =~ IDENTITY
name = $1
pub_sys = $2.nil? ? nil : $2.strip
long_name = $4.nil? ? nil : $4.strip
uri = $6.nil? ? nil : $6.strip
args = [ :start_doctype, name, pub_sys, long_name, uri ]
p args  # => [:start_doctype, "log4j", nil, nil, nil]

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

В качестве обходного пути я могу предложить вам использовать Nokogiri библиотеку. При быстром взгляде он может правильно проанализировать такой тип документа:

require 'nokogiri'

string = <<HERE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration>
</log4j:configuration>
HERE

doc = Nokogiri::XML(string)
puts doc.internal_subset.to_s
# => <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
...