Манипулирование правильно сформированным xml (на любом языке, работающем под Linux) - PullRequest
1 голос
/ 18 марта 2011

У меня правильно сформированный 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:.

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

Разъяснения:

  • xml проходит при выполнении xmllint на нем
  • Я действительно хочу решение для xml, потому что разбор xml с помощью регулярных выражений - это путь к ошибкам
  • Я не знаю имен тегов, которые могут быть между <math> и </math>
  • Не следует вносить никаких изменений в документ , за исключением префикса вышеупомянутых тегов с m:

Ответы [ 5 ]

6 голосов
/ 18 марта 2011

В 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>
4 голосов
/ 18 марта 2011

Однострочный в Perl, хорошо?

$ 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 таким образом ... но если вам достаточно вышеперечисленного ...;)

2 голосов
/ 19 марта 2011

В 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>
1 голос
/ 18 марта 2011

Возможно BeautifulSoup послужит вам лучше, чем встроенные в Python вещи. Он в основном предназначен для HTML, но может также выполнять XML, хотя ...

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

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

1 голос
/ 18 марта 2011

Лучше всего вам будет найти не проверяющий процессор XSLT и передать ему что-то вроде: <xsl:template match="math"> <m:math> <xsl:apply-templates select="@*|node()"/> </m:math> </xsl:template>

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