为什么REXML解析CDATA之前不能换行?

时间:2013-08-01 21:49:09

标签: ruby xml cdata rexml

我对Ruby非常陌生,并尝试使用先前已经完美打印的REXML(通过REXML)解析XML文档,但结果略有不稳定。

某些CDATA部分在打开XML标记之后有换行符,但在打开CDATA块之前,在这些情况下,REXML会将标记的文本解析为空。

  • 我是否可以让REXML阅读这些内容?
  • 如果没有,我可以用正则表达式或其他东西重新编写它们吗?
  • 这甚至是有效的XML吗?

这是一个示例XML文档(很少删节):

<?xml version="1.0" encoding="utf-8"?>
<root-tag>
    <content type="base64"><![CDATA[V2VsbCBkb25lISBJdCB3b3JrcyA6KQ==]]></content>
    <content type="base64">
        <![CDATA[VGhpcyB3b250IHdvcms=]]></content>

    <content><![CDATA[This will work]]></content>
    <content>
        <![CDATA[This will not appear]]></content>

    <content>
        Seems happy</content>
    <content>Obviously no problem</content>
</root-tag>

这是我的Ruby脚本(简化为最小的例子):

require 'rexml/document'
require 'base64'
include REXML

module RexmlSpike
  file = File.new("ex.xml")
  doc = Document.new file
  doc.elements.each("root-tag/content") do |contentElement|
    if contentElement.attributes["type"] == "base64"
      puts "decoded: " << Base64.decode64(contentElement.text)
    else
      puts "raw: " << contentElement.text
    end
  end
  puts "Finished."
end

我得到的输出是:

>> ruby spike.rb
  decoded: Well done! It works :)
  decoded:
  raw: This will work
  raw:

  raw:
          Seems happy
  raw: Obviously no problem
  Finished.

我在OSX Lion上使用Ruby 1.9.3p392。练习的目的最终是将一些BlogML的注释解析为Disqus使用的自定义导入XML。

3 个答案:

答案 0 :(得分:4)

为什么

<![CDATA[]]>之前的任何会覆盖<![CDATA[]]>中的任何内容。从字母到换行符(就像你发现的那样)或单个空格。这是有道理的,因为您的示例是获取元素的text,而空格则计为文本。在您能够访问<![CDATA[]]>的示例中,这是因为文本为零。


解决方案

如果查看documentation for Element,您会看到它有一个名为cdatas()的函数:

  

获取所有CData孩子的数组。不可变的。

因此,在您的示例中,如果您在contentElement.cdatas()上执行内部循环,您将看到所有遗失标记的内容。

答案 1 :(得分:3)

我建议使用Nokogiri,这是Ruby的事实XML / HTML解析器。使用它来访问<content>标签的内容,我得到:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="utf-8"?>
<root-tag>
    <content type="base64"><![CDATA[V2VsbCBkb25lISBJdCB3b3JrcyA6KQ==]]></content>
    <content type="base64">
        <![CDATA[VGhpcyB3b250IHdvcms=]]></content>

    <content><![CDATA[This will work]]></content>
    <content>
        <![CDATA[This will not appear]]></content>

    <content>
        Seems happy</content>
    <content>Obviously no problem</content>
</root-tag>
EOT

doc.search('content').each do |n|
  puts n.content
end

哪个输出:

V2VsbCBkb25lISBJdCB3b3JrcyA6KQ==

        VGhpcyB3b250IHdvcms=
This will work

        This will not appear

        Seems happy
Obviously no problem

答案 2 :(得分:2)

你的xml是有效的,但不是你期望的那样,正如@ lightswitch05指出的那样。您可以使用w3c xml validator

如果您使用的是野外世界网络中的XML,最好使用nokogiri,因为它通常用作您认为应该,而不是真的应该

旁注:这正是我避免使用XML并使用JSON的原因:XML有一个合适的定义,但无论如何似乎没有人使用它。