【问题标题】:How to wrap XML-content in a new node (Nokogiri, Ruby)?如何在新节点(Nokogiri、Ruby)中包装 XML 内容?
【发布时间】:2014-10-20 22:38:33
【问题描述】:

使用 Nokogiri 我想将一个节点 <inserted_node> 插入到以下 XML-snipplet

<foo>
   <bar>some text</bar>
</foo>

这样

<foo>
   <inserted_node>
      <bar>some text</bar>
   </inserted_node>
</foo>.

如何使用 Nokogiri 实现这一目标?

【问题讨论】:

  • &lt;foo&gt; 是根节点还是你从真正的 XML 中剪下的东西?
  • 它在 DOM 中的某个地方
  • 然后看我答案的最后一部分,其中包括在任意节点嫁接。

标签: ruby xml nokogiri


【解决方案1】:

Nokogiri 有一个方便地称为wrap 的方法。

doc.search("bar").wrap("<inserted_node>")
doc.to_html

 => <foo>
        <inserted_node><bar>some text</bar></inserted_node>
    </foo>

回答后续问题:

str = "<foo><bar1></bar1><bar2></bar2></foo>"
doc = Nokogiri::XML(str)
doc.search("bar1,bar2").map(&:parent).uniq.each do |node|
  # Create a new element to attach the children to
  inserted = doc.create_element("inserted")

  # Move the children into the new element
  inserted.children = node.children

  # Add the new element as a child of the parent node
  node << inserted
end

=> "<foo><inserted><bar1></bar1><bar2></bar2></inserted></foo>"

【讨论】:

  • 如果&lt;foo&gt; 有子节点&lt;bar1&gt;&lt;bar2&gt; 并且我想用&lt;inserted_node&gt; 包裹这两个节点呢?
  • 这有点复杂,但您基本上可以search 找到您要包装的所有节点,获取其父节点的唯一列表,然后对于每个父节点,获取其所有子节点,插入在该父节点下创建一个新节点,并将所有子节点移动到父节点下。
【解决方案2】:

我会这样做:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<foo>
   <bar>some text</bar>
</foo>
EOT

children = doc.root.children
doc.root.children = '<inserted_node>'
doc.at('inserted_node').children = children
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <foo>
# >>   <inserted_node>
# >>    <bar>some text</bar>
# >> </inserted_node>
# >> </foo>

如果有更多内容,它仍然可以正常工作:

<foo>
   <bar>some text</bar>
   <baz>some more text</baz>
</foo>

再次运行:

doc = Nokogiri::XML(<<EOT)
<foo>
   <bar>some text</bar>
   <baz>some more text</baz>
</foo>
EOT

children = doc.root.children
doc.root.children = '<inserted_node>'
doc.at('inserted_node').children = children
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <foo>
# >>   <inserted_node>
# >>    <bar>some text</bar>
# >>    <baz>some more text</baz>
# >> </inserted_node>
# >> </foo>

如果您想在 DOM 中进一步执行此操作:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<foo>
   <sub_foo>
     <bar>some text</bar>
     <baz>some more text</baz>
   </sub_foo>
</foo>
EOT

NODE_TO_INSERT = 'inserted_node'

graft_node = doc.at('sub_foo')
children = graft_node.children
graft_node.children = "<#{ NODE_TO_INSERT }>"
doc.at(NODE_TO_INSERT).children = children
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <foo>
# >>    <sub_foo><inserted_node>
# >>      <bar>some text</bar>
# >>      <baz>some more text</baz>
# >>    </inserted_node></sub_foo>
# >> </foo>

这个想法是,您通过获取该节点来指向您要修改文档的位置。我使用了doc.at('sub_foo'),因为只有一个。如果你有很多地方需要操作,你可以search,然后遍历生成的 NodeSet。一旦你知道你要处理的节点,抓住它的孩子并将它们记住在一个变量中,改变嫁接点下的孩子,然后在那个节点下重新插入旧的孩子。

一旦你掌握了这一点,你就可以轻松地破坏 XML 和 HTML。

【讨论】:

  • 非常感谢!很好的答案。
猜你喜欢
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多