У меня есть хорошо сформированный xml (открытые теги закрыты и т.д.), но там нет dtd, пространства имен не всегда корректны и существуют случайные объекты.
Я обнаружил ошибку в некоторых моих xml файлах и хочу исправить это автоматически. По существу, xml файл выглядит следующим образом:
<foo>
<bar> hi </bar>
<!-- ... -->
<math><sometag><another>bar</another></sometag></math>
<!-- ... -->
</foo>
Я хочу изменить это на
<foo>
<bar> hi </bar>
<!-- ... -->
<m:math><m:sometag><m:another>bar</m:another></m:sometag></m:math>
<!-- ... -->
</foo>
Я посмотрел на элемент Python elementtree, но в соответствии с diveintopython ему не понравится тот факт, что он не проверяет xml? Кроме того, важно, чтобы ничто не изменялось, кроме префикса m:
.
Так как я пишу кучу shell-скриптов для исправления файлов, мне действительно не нужен язык, хотя моим текущим оружием выбора является Python.
Разъяснения:
<math>
и </math>
m:
В Ruby, используя Nokogiri для массажа XML:
xml = <<EOT
<foo>
<bar> hi </bar>
<!-- ... -->
<math><sometag><another>bar</another></sometag></math>
<!-- ... -->
</foo>
EOT
NAMESPACE = %w[m http://host.com/m]
require 'nokogiri'
doc = Nokogiri::XML::DocumentFragment.parse(xml)
ns = doc.at('foo').add_namespace_definition(*NAMESPACE)
doc.xpath('foo/math | foo/math//*').each { |n| n.namespace = ns }
puts doc.to_xml
Результат выглядит следующим образом:
>> <foo xmlns:m="http://host.com/m">
>> <bar> hi </bar>
>> <!-- ... -->
>> <m:math><m:sometag><m:another>bar</m:another></m:sometag></m:math>
>> <!-- ... -->
>> </foo>
Если пространство имен не может быть добавлено в <foo>
, вы можете напрямую пропустить имена тегов, не входя в пространства имен:
xml = <<EOT
<foo>
<bar> hi </bar>
<!-- ... -->
<math><sometag><another>bar</another></sometag></math>
<!-- ... -->
</foo>
EOT
NAMESPACE = %w[m http://host.com/m]
require 'nokogiri'
doc = Nokogiri::XML::DocumentFragment.parse(xml)
doc.xpath('foo/math | foo/math//*').each { |n| n.name = "m:" << n.name }
puts doc.to_xml
# >> <foo>
# >> <bar> hi </bar>
# >> <!-- ... -->
# >> <m:math><m:sometag><m:another>bar</m:another></m:sometag></m:math>
# >> <!-- ... -->
# >> </foo>
В Perl вы можете использовать XML:: Twig, например:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
XML::Twig->new( twig_roots => { math => \&add_prefix },
twig_print_outside_roots => 1,
)
->parse( \*DATA);
sub add_prefix
{ my( $t, $math)= @_;
foreach my $m ( $math, $math->descendants( '#ELT'))
{ $m->set_tag( "m:" . $m->tag); }
$t->flush;
}
__DATA__
<foo>
<bar> hi </bar>
<!-- ... -->
<math><sometag><another>bar</another></sometag></math>
<!-- ... -->
</foo>
Один слой в Perl ok?
$ perl -lne'm!<math>.*</math>! and s!<(/)?([^>]+)>!<$1m:$2>!gm;print' 5351382.txt
<foo>
<bar> hi </bar>
<!-- ... -->
<m:math><m:sometag><m:another>bar</m:another></m:sometag></m:math>
<!-- ... -->
</foo>
Вы не должны разбираться с XML таким образом... но если выше для вас достаточно...;)
<!-- -->
на <m:!-- -->
. Поэтому я бы предпочел сделать это с помощью библиотеки xml.
m!! and s!!!
строительство. Не могли бы вы объяснить, как это работает, или указать на сайт, который это объясняет? Я сделал довольно много perl oneliners, но не знал эту конструкцию.
Возможно, BeautifulSoup будет служить вам лучше, чем встроенный материал Python. Он в основном предназначен для HTML, но также может делать XML, хотя...
Класс BeautifulSoup полон эвристик, основанных на веб-браузере, для того, чтобы предсказать намерение авторов HTML. Но у XML нет фиксированного набора тегов, поэтому эти эвристики не применяются. Поэтому BeautifulSoup не очень хорошо выполняет XML.
Это может быть не идеально, но, вероятно, лучше работает на неопределенный или недопустимый XML, чем это делает строгий парсер. Еще один момент в его пользу заключается в том, что он дает вам Unicode, dammit.
Лучше всего, скорее всего, найти невращающийся процессор XSLT и передать ему что-то вроде:
<xsl:template match="math">
<m:math>
<xsl:apply-templates select="@*|node()"/>
</m:math>
</xsl:template>
m:
к тегам внутри тега <math>, верно? И я не знаю названий тегов, которые могут встречаться между <math>
и </math>
.
select="@*|node()"
.