Ruby中的XML解析

4

我正在使用REXML Ruby解析器来解析一个XML文件。但是在64位AIX服务器上,使用64位Ruby时,我遇到了以下错误:

REXML::ParseException: #<REXML::ParseException: #<RegexpError: Stack overflow in 
regexp matcher: 
/^<((?>(?:[\w:][\-\w\d.]*:)?[\w:][\-\w\d.]*))\s*((?>\s+(?:[\w:][\-\w\d.]*:)?[\w:][\-\w\d.]*\s*=\s*(["']).*?\3)*)\s*(\/)?>/mu>

这里需要翻译的内容是:“调用方式如下:”
REXML::Document.new(File.open(actual_file_name, "r"))

有没有关于如何解决这个问题的想法?


1
这是你的强大正则表达式还是来自REXML? - Niklas B.
这是来自REXML。这不是我编写的正则表达式。我只是使用REXML解析一个XML文档。 - Ricketyship
1
所以,REXML正在提供那个“巨兽级的正则表达式”:D - Ricketyship
2个回答

12

我在使用REXML时遇到了一些问题,它似乎不是最成熟的库。通常我会使用Nokogiri来进行Ruby XML解析,它应该比REXML更快、更稳定。通过sudo gem install nokogiri安装后,你可以使用以下代码获取DOM实例:

doc = Nokogiri.XML(File.open(actual_file_name, 'rb'))
# => #<Nokogiri::XML::Document:0xf1de34 name="document" [...] >

个人认为,官方网页上的文档比REXML好得多。


1
我想知道这是否是Ruby 64位特定的问题。在32位系统上无法重现相同的问题。如果有解决方法,而不是安装其他库,那就更好了。 - Ricketyship
那么为什么同一个文件可以在32位的Ruby中解析?理论上,64位的Ruby应该能够执行32位Ruby库所做的所有活动。是64位的Ruby有一些限制吗?如果有,是否有任何相关文档? - Ricketyship
@Barath:不,我认为这是一个bug。正如我所说的,这并不让我感到惊讶,因为大多数人现在已经使用Nokogiri而不是REXML了。 - Niklas B.
该文件只有两层嵌套。文件本身只有约54kb大小。因此我不确定是什么原因导致了这个问题。 - Ricketyship
以下错误被抛出:ActionView::TemplateError: too big quantifier in {,}: /(.{1,800})(\s+|$)/ ... 当我深入研究Ruby代码时,我发现word_wrap正在使用正则表达式匹配。这失败了。即使在irb上,同样的问题仍然存在。最后,我不得不减少正则表达式可以重复的次数,即{,}值。然后它就起作用了。而且最重要的是,这发生在32位AIX盒子上!!!所以显然,某个地方有一些限制。 - Ricketyship
显示剩余3条评论

6

我几乎立即找到了答案。

我所做的第一件事是在ruby源代码中搜索被抛出的错误。

我发现这是由regex.h引起的。

在regex.h中,代码流程大致如下:

/* Maximum number of duplicates an interval can allow.  */
#ifndef RE_DUP_MAX
#define RE_DUP_MAX  ((1 << 15) - 1)
#endif

现在这里的问题是RE_DUP_MAX。在AIX系统中,同样的常量已经在/usr/include某个地方定义过了。 我搜索了一下,在找到了它。

/usr/include/NLregexp.h
/usr/include/sys/limits.h
/usr/include/unistd.h

我不确定其中的三个文件中哪一个被使用(很可能是NLregexp.h)。在这些头文件中,RE_DUP_MAX的值被设置为255!因此,对正则表达式重复次数有了限制!简而言之,原因在于编译采用的是系统定义的值,而不是我们在regex.h中自定义的值!这也回答了我最近提出的问题:Regex limit in ruby 64 bit aix compilation。我不能立即回答它,因为我需要至少100点声望:D:D,谢谢!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接