2016-09-30 60 views
0

我有以下XML:如何节点集内进行搜索,并从同一节点集删除一个节点

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
    <w:document mc:Ignorable="w14 w15 wp14" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"> 
     <w:body> 
      <w:p w14:paraId="56037BEC" w14:textId="1188FA30" w:rsidR="001665B3" w:rsidRDefault="008B4AC6"> 
       <w:r> 
        <w:t xml:space="preserve">This is the story of a man who </w:t> 
       </w:r> 
       <w:ins w:author="Mitchell Gould" w:date="2016-09-28T09:15:00Z" w:id="0"> 
        <w:r w:rsidR="003566BF"> 
         <w:t>went</w:t> 
        </w:r> 
       </w:ins> 
       <w:del w:author="Mitchell Gould" w:date="2016-09-28T09:15:00Z" w:id="1"> 
        <w:r w:rsidDel="003566BF"> 
         <w:delText>goes</w:delText> 
        </w:r> 
       </w:del> 
... 

我用引入nokogiri解析XML如下:

zip = Zip::File.open("test.docx") 
doc = zip.find_entry("word/document.xml") 
file = Nokogiri::XML.parse(doc.get_input_stream) 

我有一个德尔元素:一个包含所有W的“删除”节点集

@deletions = file.xpath("//w:del") 

我这个节点集内搜索,看是否元素EXI sts如下:

my_node_set = @deletions.search("//w:del[@w:id='1']" && "//w:del/w:r[@w:rsidDel='003566BF']") 

如果存在,我想从删除节点集中删除它。我这样做与以下内容:

deletions.delete(my_node_set.first) 

这似乎工作,因为没有错误返回,它显示终端中删除的节点集。

然而,当我检查我的@deletions NODESET似乎该项目还有:

@deletions.search("//w:del[@w:id='1']" && "//w:del/w:r[@w:rsidDel='003566BF']") 

我只是让我的周围引入nokogiri头,所以我显然不是搜索的元素妥善内我的@deletions节点集,而不是搜索整个文档。

如何搜索元素的@deletions节点集的内部,然后将其从节点集中删除?

+0

请阅读“[mcve]”。我们需要一个语法正确的XML示例,它是展示问题所需的最低限度的必需条件。我建议删除命名空间,因为它们与问题没有密切关系。 –

+0

目前尚不清楚为什么你想有选择地从NodeSet中删除。 NodeSets就像指向文档中节点的指针数组。从数组中删除一个节点,实际上你所做的只是从树中删除特定的分支,换句话说,就是从文档中删除该标签。如果您正在收集一堆节点,那么只想删除一个节点,然后只搜索该节点并将其删除。不要浪费时间和内存来收集NodeSet。 –

回答

0

考虑一下:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<html> 
    <body> 
    <div id="foo"><p>foo</p></div> 
    <div id="bar"><p>bar</p></div> 
    </body> 
</html> 
EOT 

divs包含div标签,这是一个节点集:

divs = doc.css('div') 
divs.class # => Nokogiri::XML::NodeSet 

而且包含:

divs.to_html # => "<div id=\"foo\"><p>foo</p></div><div id=\"bar\"><p>bar</p></div>" 

您可以在节点集使用at搜索找到第一个匹配项:

divs.at('#foo').to_html # => "<div id=\"foo\"><p>foo</p></div>" 

而且你可以很容易地将其删除:

divs.at('#foo').remove 

从文件本身删除它:

puts doc.to_html 

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
# >> <html> 
# >> <body> 
# >>  
# >>  <div id="bar"><p>bar</p></div> 
# >> </body> 
# >> </html> 

从节点集删除它,但我们不关心它,NodeSet只是一个指向文档本身的节点的指针,用于给出要删除的内容列表。

如果你再删除某些节点后要更新的节点集,重新扫描文档和重建节点集:

divs = doc.css('div') 
divs.to_html # => "<div id=\"bar\"><p>bar</p></div>" 

如果你的目标是消除在节点集的所有节点,而不是通过该列表搜索你可以简单地使用:

divs.remove 
puts doc.to_html 

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
# >> <html> 
# >> <body> 
# >>  
# >>  
# >> </body> 
# >> </html> 

当我删除节点,我不收集中间节点集,而不是我使用类似做对飞

删除#bar中嵌入的<p>标记。通过放宽选择和at更改为search我可以删除它们成群:

doc.search('div p').remove 

puts doc.to_html 

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
# >> <html> 
# >> <body> 
# >>  <div id="foo"></div> 
# >>  <div id="bar"></div> 
# >> </body> 
# >> </html> 

如果坚持通过节点集走,记住,他们就像数组,你可以这样对待他们。下面是使用reject跳过一个特定节点的例子:

doc = Nokogiri::HTML(<<EOT) 
<html> 
    <body> 
    <div id="foo"><p>foo</p></div> 
    <div id="bar"><p>bar</p></div> 
    </body> 
</html> 
EOT 

divs = doc.search('div').reject{ |d| d['id'] == 'foo' } 
divs.map(&:to_html) # => ["<div id=\"bar\"><p>bar</p></div>"] 

您将不会收到一个节点集,虽然,你会得到一个数组:

divs.class # => Array 

虽然你可以做到这一点,你”重新使用特定的选择器来减少集合,而不是依靠Ruby来访问selectreject元素。

+0

对于这种解释和指导,我无法表达谢意。我错误地认为Nodeset就像一个单独的阵列,我可以删除项目而不影响文档。我现在有了更好的理解。 – chell