我正试图用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_css
和at_xpath
是css
和xpath
搜索之后的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文档,看看还有什么可用的,以及哪些适合您的需求。您可能会变得更加复杂,但通常替换节点或移动节点是一个非常简单的过程。