使用css在Nokogiri :: XML :: NodeSet中设置属性

时间:2014-01-29 00:30:11

标签: css ruby xml nokogiri

我试图为xml文件中的特定元素设置属性,并且我使用

取得了成功
doc.css('Object').attr("Id").value = timestamp

这种情况很好,直到“对象”不存在导致程序中出现异常并退出的情况。为了避免这种情况,我想使用Nodeset,因为它只是空的。

doc.css('Object').each do |element|
    element.attr("Id").value = timestamp
end

然而,这返回错误,value =是一个未定义的方法。它可能很简单,但我是Ruby和CSS的新手,所以任何帮助都会很棒。

1 个答案:

答案 0 :(得分:2)

这个问题与CSS没什么关系,因为Nokogiri使用CSS选择器作为使用XPath选择器的替代方法,而且它们都只用于提供节点或节点的路径。

看起来你正在过度思考这个问题,并使其变得比它需要的更难。这就是我要做的事情:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<xml>
  <foo>
    <Object>bar</Object>
  </foo>
</xml>
EOT

doc.at('Object')["Id"] = Time.now.to_s

此时查看doc显示:

puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <xml>
# >>   <foo>
# >>     <Object Id="2014-01-28 19:13:32 -0700">bar</Object>
# >>   </foo>
# >> </xml>

了解atat_cssat_xpath之间的区别非常重要,它们会返回第一个匹配的Nodesearch,{{3返回NodeSets的{}和cssxpath类似于包含节点的数组。当你知道,你的陈述:

doc.css('Object').attr("Id").value = timestamp

没有多大意义,特别是因为那不是NodeSet方法的定义方式:

attr(key, value = nil, &blk) 

您需要使用:

doc.css('Object').attr("Id", value)

value分配给文档中每个Id节点的所有<Object>属性。

但是,再次,这不是正确的选择,而是应该使用atat_css来返回单个节点。

  

在“对象”不存在的情况下,这很好。

如果不存在<Object>节点,则它会变得更有趣,您必须确定要执行的操作。您可以插入它,或者,您可以简单地移动并且什么都不做。

查看节点是否存在很简单:

object_node = doc.at('Object')
if object_node
  object_node['Id'] = Time.now.to_s
else
  # ... insert it
end

要插入节点涉及找到要插入的位置,然后添加它:

doc.at('foo').add_child("<Object Id='#{ Time.now }'>baz</Object>")
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <xml>
# >>   <foo>
# >>     <Object>bar</Object>
# >>   <Object Id="2014-01-28 19:39:38 -0700">baz</Object></foo>
# >> </xml>

我没有尝试使XML输出漂亮,这在XML中并不重要,它只需要在语法上正确。

另请注意,通过将节点或节点定义为XML字符串,可以插入节点或节点。 Nokogiri会将其解析为适当的XML并将其移植到您所说的位置。你也可以通过定义NodeSet或Node然后插入它来走很长的路线,但是,一般来说,这会产生更丑陋的代码并导致你做更多的工作,这会导致那些跟随你的脚步的人的代码可读性降低保持来源。