变异Nokogiri XML文档对象



我正试图用Nokogiri编辑一个大的XML文件。目前,我可以使用.css找到我正在寻找的NodeSet。我可以创建我想设置的新NodeSet作为替换,但通过使用Nokogiri::XML::NodeSet#push,我无法更改xml文档对象的内容。

xml = Nokogiri::XML(File.read('/Users/Desktop/metadata.xml')
keywords = xml.css('version').first.css('keywords keyword') ## node set I want to edit
keywords.delete(keywords[0]) ## one less element in the node set
xml.css('version').first.css('keywords keyword').remove ## destructively modifies xml object and erases all elements
## this is where things get interesting: 
## this call returns a new node set with keywords[0] inside of it, 
## but does NOT mutate the xml object
xml.css('version').first.css('keywords keyword').push(keywords[0])
puts xml.css('version').first.css('keywords keyword') ## puts an empty array

编辑:示例XML

<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords>
      <keyword>this</keyword>
      <keyword>that</keyword>
      <keyword>the other</keyword>
    </keywords>
  </locale>
</version>

编辑:目标XML

<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords>
      <keyword>that</keyword>
      <keyword>the other</keyword>
    </keywords>
  </locale>
</version>

OR

<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords>
      <keyword>different keyword</keyword>
    </keywords>
  </locale>
</version>

如果没有XML示例,我会推迟诊断问题,但是您的代码写得不好。这些似乎是有效的替代/更改:

  • keywords = xml.css('version').first可以简化为:

    xml.at('version')
    
  • xml.css('version').first.css('keywords keyword')可以缩短为:

    xml.css('version 'keywords keyword')
    

但如果没有XML,我无法证实这一点。

Nokogiri的at('some_selector')等价于search('some_selector').first。类似地,at_cssat_xpathcssxpath搜索之后的first的等价物。


我是这样写的:

require 'nokogiri'
xml = Nokogiri::XML(<<EOT)
<xml>
<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords>
      <keyword>this</keyword>
      <keyword>that</keyword>
      <keyword>the other</keyword>
    </keywords>
  </locale>
</version>
</xml>
EOT
keywords = xml.css('version keywords keyword')
xml.at('version keywords').children = keywords[1..-1]
puts xml.to_xml

哪个输出:

<?xml version="1.0"?>
<xml>
<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords><keyword>that</keyword><keyword>the other</keyword></keywords>
  </locale>
</version>
</xml>

为了使XML正确,<version>需要一个包装"根"标记,这就是我添加<xml>的原因。我相信您的原始XML也有类似的内容。

您可以通过对keywords节点集进行切片来控制允许保留多少以及哪些现有的<keyword>节点。


这并没有以一种足够通用的方式来解决这个问题,以至于我可以添加和修改现有的子项。

require 'nokogiri'
xml = Nokogiri::XML(<<EOT)
<xml>
<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords>
      <keyword>this</keyword>
      <keyword>that</keyword>
      <keyword>the other</keyword>
    </keywords>
  </locale>
</version>
</xml>
EOT
version_keywords = xml.at('version keywords')
keywords = version_keywords.css('keyword')
version_keywords.children = keywords[1..-1]
version_keywords.add_child('<keyword>And now for something entirely different</keyword>')
puts xml.to_xml
<?xml version="1.0"?>
<xml>
<version>
  <locale name="en-US">
    <title>This is the Title</title>
    <description>this is the description</description>
    <keywords><keyword>that</keyword><keyword>the other</keyword><keyword>And now for something entirely different</keyword></keywords>
  </locale>
</version>
</xml>

您可以简单地通过识别节点的位置来添加节点,然后使用多种方法中的一种来插入新的节点。您甚至可以操作keywords并传递整个NodeSet。可以使用字符串,也可以创建新的节点实例。野村对任何一个都很满意。

这些是查找和更改节点或其子节点所需的一些工具。您需要花一些时间阅读Nokogiri的XML::Node文档,看看还有什么可用的,以及哪些适合您的需求。您可能会变得更加复杂,但通常替换节点或移动节点是一个非常简单的过程。

相关内容

  • 没有找到相关文章

最新更新