操作格式良好的xml(在linux下运行的任何语言)

时间:2011-03-18 11:35:59

标签: python ruby xml perl

我有格式良好的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。

澄清:

  • xml在执行xmllint时传递
  • 我真的想要一个xml解决方案,因为使用正则表达式解析xml是一种解决方法
  • 我不知道<math></math>
  • 之间的代码名称
  • 不应对文档进行任何修改,除了上述标记的前缀m:

5 个答案:

答案 0 :(得分:6)

在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>

答案 1 :(得分:4)

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 :(得分:2)

在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>

答案 3 :(得分:1)

您最好的选择可能是找到一个非验证的XSLT处理器并传递给它: <xsl:template match="math"> <m:math> <xsl:apply-templates select="@*|node()"/> </m:math> </xsl:template>

答案 4 :(得分:1)

也许BeautifulSoup会比Python内置的东西更好地为你服务。它主要是为HTML设计的,但也可以做XML,虽然......

  

BeautifulSoup类充满了类似Web浏览器的启发式方法,用于划分HTML作者的意图。但XML没有固定的标记集,因此这些启发式方法不适用。所以BeautifulSoup不能很好地完成XML。

它可能不完美,但可能在未指定或无效的XML上比严格的解析器更好。有利于它的另一点是gives you Unicode, dammit