如何抓取一个节点并将其作为一个新对象进行处理
How to grab a node and work on it as a new object
我需要从一个大的 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.xpath
时,我实际上是 运行 在 doc
上使用它。但我想获取一个特定的节点及其子节点,然后将其作为一个新对象进行处理。这将极大地缩小大海捞针的范围,并使我的其余工作变得更加轻松!
如何仅使用我选择的节点创建新对象?我想将 section[3]
变成一个看不到其他 <part>
及其关联的 <section>
标签的新对象。
"//part"
表示“从文档的顶部开始搜索到底部,找到所有 <part>
个节点。
这不是你想要的。
相反你想要:
"./part"
这意味着“从当前位置开始并在其中搜索。
最容易将 XPath 想象成您在磁盘上的目录结构中导航。如果你想在你使用的驱动器的根目录下找到一个文件:
/foo
如果您想在当前目录中查找文件,您可以使用:
./foo
XPath 使用 //
表示 "search from the top to the bottom":
//foo
除非我需要 XPath 的强大功能,否则我建议使用 CSS 选择器而不是 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 它非常简单。
另见“”。
使用to_xml
将temp
变回XML字符串,然后再次使用Nokogiri::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::HTML
,但如果您认为需要,可以在此处将其替换为 XML
。)
我需要从一个大的 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.xpath
时,我实际上是 运行 在 doc
上使用它。但我想获取一个特定的节点及其子节点,然后将其作为一个新对象进行处理。这将极大地缩小大海捞针的范围,并使我的其余工作变得更加轻松!
如何仅使用我选择的节点创建新对象?我想将 section[3]
变成一个看不到其他 <part>
及其关联的 <section>
标签的新对象。
"//part"
表示“从文档的顶部开始搜索到底部,找到所有 <part>
个节点。
这不是你想要的。
相反你想要:
"./part"
这意味着“从当前位置开始并在其中搜索。
最容易将 XPath 想象成您在磁盘上的目录结构中导航。如果你想在你使用的驱动器的根目录下找到一个文件:
/foo
如果您想在当前目录中查找文件,您可以使用:
./foo
XPath 使用 //
表示 "search from the top to the bottom":
//foo
除非我需要 XPath 的强大功能,否则我建议使用 CSS 选择器而不是 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 它非常简单。
另见“
使用to_xml
将temp
变回XML字符串,然后再次使用Nokogiri::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::HTML
,但如果您认为需要,可以在此处将其替换为 XML
。)