0

我正在尝试使用 Nokogiri 编辑一个大的 XML 文件。目前,我能够找到我正在寻找的 NodeSet,.css我可以创建我想设置为替换的新 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>

或者

<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>
4

1 回答 1

0

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

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

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

    xml.css('version 'keywords keyword')
    

但如果没有 XML,我无法确认。

Nokogiriat('some_selector')相当于search('some_selector').first. 类似地at_css,和at_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 有类似的东西。

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


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

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。你可以使用一个字符串,或者创建一个新的 Node 实例。Nokogiri 对其中任何一个都很满意。

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

于 2013-06-26T19:02:41.947 回答