如何抓取节点并将其作为新对象进行处理

How to grab a node and work on it as a new object

提问人:Tim Morton 提问时间:11/12/2015 最后编辑:the Tin ManTim Morton 更新时间:4/25/2017 访问量:104

问:

我需要从大型XML文件中提取一个片段,并且只处理该片段。

xml = <<XMLEND
<CFRDOC xsi:noNamespaceSchemaLocation="CFRMergedXML.xsd">
    <TITLE>
        <SUBTITLE>
            <CHAPTER>
                <TOC></TOC>
                <PART></PART>
                <PART></PART>
                <PART>
                    <EAR>Pt. 1903</EAR>
                    <HD SOURCE="HED">PART 1903—INSPECTIONS, CITATIONS AND PROPOSED PENALTIES</HD>
                    <CONTENTS></CONTENTS>
                    <AUTH></AUTH>
                    <SOURCE></SOURCE>
                    <SECTION>section1</SECTION>
                    <SECTION>section2</SECTION>
                    <SECTION>section3</SECTION>
                    <SECTION>section4</SECTION>
                </PART>
            </CHAPTER>
        </SUBTITLE>
    </TITLE>
</CFRDOC>
XMLEND

doc = Nokogiri::HTML(xml)

section = doc.xpath("//section")

# I can grab a specific node...
section[3].text          
=> "section4"

# copy it 
temp = section[3].dup
=> #<Nokogiri::XML::Element:0x261ce64 name="section" children=[#<Nokogiri::XML::Text:0x261c98c "section4">]>

# but the variable still refers to the whole...
doc.xpath("//part").size
=> 3
section.xpath("//part").size
=> 3
temp.xpath("//part").size 
=> 3

来自PHP背景,我不得不重新考虑变量。我知道 Ruby 中的变量是不同的;它们是指向对象的指针。

因此,当我运行时,我实际上是在运行它。但是我想抓住一个特定的节点及其子节点,然后将其作为新对象进行处理。这将大大缩小大海捞针的范围,并使我的其余工作变得更加轻松!temp.xpathdoc

如何仅使用我选择的节点创建新对象?我想变成一个新对象,它不会看到另一个及其相关标签。section[3]<part><section>

Ruby Nokogiri 引用传递

评论

0赞 ABC123 10/16/2016
您是否找到 CFRMergedXML.xsd 来验证 cfrdoc?您是否必须将 xsd 与 xjb 结合起来?

答:

2赞 the Tin Man 11/12/2015 #1

"//part"意思是“从文档的顶部开始,搜索到底部,找到所有节点。<part>

那不是你想要的。

相反,您需要:

"./part"

这意味着“从当前位置开始并在其中搜索。

最简单的方法是将 XPath 视为在磁盘上导航目录结构。如果要在驱动器的根目录下查找文件,请使用:

/foo

如果您想在当前目录中查找文件,请使用:

./foo

XPath 用来表示“从上到下搜索”://

//foo

我建议使用 CSS 选择器而不是 XPath,除非我需要 XPath 的强大功能。我发现 XPath 在视觉上很嘈杂。所以,相反,我会使用:

section = doc.search('section')

section.search('part')

现在,沉思一下:

require 'nokogiri'

xml = <<XMLEND
<CFRDOC xsi:noNamespaceSchemaLocation="CFRMergedXML.xsd">
  <TITLE>
    <SUBTITLE>
      <CHAPTER>
        <PART></PART>
        <PART>
          <SECTION>section1</SECTION>
          <SECTION>section2</SECTION>
          <SECTION>section3</SECTION>
          <SECTION>section4</SECTION>
        </PART>
      </CHAPTER>
    </SUBTITLE>
  </TITLE>
</CFRDOC>
XMLEND

doc = Nokogiri::XML(xml)

为了便于阅读,我减少了 XML。

doc.search('SECTION').map(&:text) # => ["section1", "section2", "section3", "section4"]
doc.search('PART').size # => 2
doc.search('PART[2]').text # => "\n          section1\n          section2\n          section3\n          section4\n        "
doc.search('PART[2]').search('SECTION').map(&:text) # => ["section1", "section2", "section3", "section4"]
doc.search('PART[2] SECTION').map(&:text) # => ["section1", "section2", "section3", "section4"]
doc.search('PART SECTION').map(&:text) # => ["section1", "section2", "section3", "section4"]

使用简单的选择器,可以轻松钻取到文档中。有时不可能编写一个简单的选择器,因此我们必须在文档中找到航点并从中导航,但基于示例 XML 它非常简单。

另请参阅“如何避免在抓取时加入节点中的所有文本”。

评论

0赞 Tim Morton 11/12/2015
感谢您的快速回复。是的,这是一个“全局”搜索,但政府XML经常无法以合乎逻辑的方式封装内容。为了我自己的理智,我想提取一个较小的块来使用。换句话说,我想对较小的子集进行搜索,因为有时我正在寻找的内容被包装在另一个节点中,有时不是 - 所以我倾向于使用//////
0赞 Tim Morton 11/12/2015
啊,当我发表评论时,你扩展了你的答案。这看起来确实很干净,而且引用特定节点看起来要简单得多。我必须考虑这一点。
0赞 the Tin Man 11/12/2015
您会发现完整的答案需要一段时间才能生成,并且通常会经过多次更新才能稳定下来。(我们中的许多人在回答之前会等待一段时间,看看我们是否喜欢答案的方向;我不需要积分,我只想看到合理的答案。因此,最好先等待一天,然后再开始分析和选择答案。
0赞 the Tin Man 11/12/2015
干净的代码是必不可少的,无论是在编写代码时,还是在几个月或几年后返回代码时更是如此。我喋喋不休地强调可维护性和我们可以快速摸索的代码,在凌晨 3:00 世界处于火焰中时要好得多。
0赞 Tim Morton 11/12/2015
注意到并赞赏:)当你被难住时很难等待:/我有一个后续问题:当我测试它时,它似乎只适用于而不是?不知道这是怎么回事。doc.search()Nokogiri::HTML()Nokogiri::XML()
1赞 user513951 11/12/2015 #2

用于转换回 XML 字符串,然后再次用于获取新对象。to_xmltempNokogiri::XML

my_section = Nokogiri::XML(temp.to_xml)
my_section.xpath('//part').size
# => 0

puts my_section
# <?xml version="1.0"?>
# <section><section4</section>

(我不确定你为什么要开始使用,但如果你认为需要,你可以在这里用它代替。Nokogiri::HTMLXML

评论

0赞 Tim Morton 11/12/2015
现在我看到了,很明显......我使用而不是 .但对于我的生活,我不记得它是什么,或者这是否是一个很好的理由Nokogiri::HTMLNokogiri::XML
1赞 the Tin Man 11/12/2015
使用 HTML 变体进行解析会导致对 XML 应用更严格的限制。请参阅定义 rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/...。HTML 是“该死的草率”(我的话),但这就是 libXML 理解 HTML 所需要的。使用有效,但使用 或 更合适。Nokogiri::XMLDEFAULT_XMLto_sto_xmlto_xhtmlto_htmlto_s