【问题标题】:Adding a node using Nokogiri使用 Nokogiri 添加节点
【发布时间】:2014-09-02 11:45:47
【问题描述】:

我有一个 HTML 字符串(例如 <div class="input">hello</div>),并且我只想在字符串中的 HTML 标记是 label(例如 <label>Hi</label>)时添加一个节点。

doc = Nokogiri::XML(html)

doc.children.each do |node|
  if node.name == 'label'
    # this code gets called
    span = Nokogiri::XML::Node.new "span", node
    span.content = "hello"

    puts span.parent 
    # nil

    span.parent = node
    # throws error "node can only have one parent"
  end
end

doc.to_html # Does not contain the span.

我一生都无法理解我做错了什么,任何帮助都会非常感激。

编辑:这解决了我的问题,感谢您的回答!

# notice DocumentFragment rather than XML
doc = Nokogiri::HTML::DocumentFragment.parse(html_tag)
doc.children.each do |node|
  if node.name == 'label'
    span = Nokogiri::XML::Node.new "span", doc
    node.add_child(span)
  end
end

【问题讨论】:

  • 您希望新跨度显示在哪里?
  • 您需要展示一个示例,说明您的输出/结果 HTML 应该是什么样子。

标签: ruby-on-rails ruby nokogiri


【解决方案1】:

添加/更改/删除 HTML 很容易:

require 'nokogiri'

doc = Nokogiri::HTML::DocumentFragment.parse('<div class="input">hello</div>')
div = doc.at('div')
div << '<span>Hello</span>'
puts doc.to_html

结果:

# >> <div class="input">hello<span>Hello</span>
# >> </div>

请注意,由于&lt;&lt;,上述代码将一个新节点附加到&lt;div&gt; 的现有子节点,这意味着它们被附加在包含“hello”的文本节点之后

如果你想覆盖孩子,你可以使用children =轻松做到这一点:

div.children = '<span>Hello</span>'
puts doc.to_html

结果:

# >> <div class="input"><span>Hello</span></div>

children = 可以采用单个节点,该节点下可以有多个其他节点,或者插入的节点的 HTML 文本。这就是node_or_tagsthe documentation 中看到的意思。

也就是说,要更改嵌入的 &lt;label&gt;,我会这样做:

doc = Nokogiri::HTML::DocumentFragment.parse('<div class="input"><label>hello</label></div>')
label = doc.at('div label')
label.name = 'span' if label
puts doc.to_html
# >> <div class="input"><span>hello</span></div>

或者:

doc = Nokogiri::HTML::DocumentFragment.parse('<div class="input"><label>hello</label></div>')
label = doc.at('div label')
label.replace("<span>#{ label.text }</span>") if label
puts doc.to_html
# >> <div class="input"><span>hello</span></div>

Nokogiri 可以在您指向标签后轻松更改标签名称。您可以通过将#{ label.text } 替换为您想要的任何内容来轻松更改&lt;span&gt; 中的文本。

at('div label') 是查找特定节点的一种方法。它基本上意味着“在第一个 div 中找到第一个标签标签”。 at 表示查找第一个,类似于使用search(...).first。如果您需要,Nokogiri::XML::Node documentation 中有 atsearch 的 CSS 和 XPath 等效项。

【讨论】:

  • 这修复了它,当我应该使用 Nokogiri::HTML::DocumentFragment:: 时,我使用了 Nokogiri::XML::。 :-)
  • 使用DocumentFragment.parse和普通解析的区别在于,在后面,Nokogiri创建了一个带有&lt;html&gt;&lt;body&gt;标签的DOM,基本上是在做修复,试图在语法上创建一个正确的文件。
  • 是否有向片段添加父级的方法?我需要在一个 div 中包装和 iframe,并为该 div 指定一个特定的类。
  • @ZackHerbert 为此创建一个单独的问题。在评论中提出新问题会劫持当前问题,并且不允许我们正确回答。请参阅“How to Ask”以及链接页面。您的问题已在有关 Nokogiri 的许多页面中得到解答,因此请先搜索再提问。 meta.stackoverflow.com/q/261592/128421
【解决方案2】:

一些问题 - 您 span = .. 行正在创建节点,但实际上并未将其添加到文档中。此外,您无法在创建它的块之外访问span

我想这就是你所追求的:

html = '<label>Hi</label>'

doc = Nokogiri::XML(html)

doc.children.each do |node|
  if node.name == 'label'
    # this code gets called
    span = Nokogiri::XML::Node.new "span", doc
    span.content = "hello"
    node.add_child(span)
  end
end

# NOTE: `node` nor `span` are accessible outside of the each block

doc.to_s # => "<?xml version=\"1.0\"?>\n<label>Hi<span>hello</span></label>\n"

注意node.add_child(span) 这一行。

【讨论】:

  • 是的,很抱歉显示令人困惑的代码。对 puts (for span) 的调用实际上是 inside 块。
猜你喜欢
  • 1970-01-01
  • 2012-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 2017-05-27
相关资源
最近更新 更多