如何使用Nokogiri读卡器接口告知节点的行号?

时间:2011-04-09 09:25:25

标签: ruby xml nokogiri

我正在尝试编写一个Nokogiri脚本,它将为包含ASCII双引号(«“»)的文本节点grep XML。由于我想要类似grep的输出,我需要行号,以及每行的内容但是,我无法看到如何分辨元素起始处的行号。这是我的代码:

require 'rubygems'
require 'nokogiri'

ARGV.each do |filename|
    xml_stream = File.open(filename)
    reader = Nokogiri::XML::Reader(xml_stream)
    titles = []
    text = ''
    grab_text = false
    reader.each do |elem|
        if elem.node_type == Nokogiri::XML::Node::TEXT_NODE
            data = elem.value
            lines = data.split(/\n/, -1);

            lines.each_with_index do |line, idx|
                if (line =~ /"/) then
                    STDOUT.printf "%s:%d:%s\n", filename, elem.line()+idx, line
                end
            end
        end
    end
end

elem.line()不起作用。

1 个答案:

答案 0 :(得分:4)

XML和解析器实际上没有行号的概念。你在谈论文件的物理布局。

您可以使用访问器与解析器一起玩游戏,以查找包含换行符和/或回车符的文本节点,但由于XML允许嵌套节点,因此可以将其抛弃。

require 'nokogiri'

xml =<<EOT_XML
<atag>
  <btag>
    <ctag 
      id="another_node">
      other text
    </ctag>
  </btag>
  <btag>
    <ctag id="another_node2">yet
                             another
                             text</ctag>
    </btag>
  <btag>
    <ctag id="this_node">this text</ctag>
  </btag>
</atag>
EOT_XML

doc = Nokogiri::XML(xml)

# find a particular node via CSS accessor
doc.at('ctag#this_node').text # => "this text"

# count how many "lines" there are in the document
doc.search('*/text()').select{ |t| t.text[/[\r\n]/] }.size # => 12

# walk the nodes looking for a particular string, counting lines as you go
content_at = []
doc.search('*/text()').each do |n|
  content_at << [n.line, n.text] if (n.text['this text'])
end
content_at # => [[14, "this text"]]

这是有效的,因为解析器能够找出什么是文本节点并干净地返回它,而不依赖于正则表达式或文本匹配。


编辑:我经历了一些旧代码,在Nokogiri的文档中窥探了一些,并提出了上述编辑后的更改。它工作正常,包括处理一些病理情况。 Nokogiri FTW!