使用Nokogiri XPath(带有XML命名空间)在XML中搜索节点

4
我发现Nokogiri在处理xml方面非常强大,但我遇到了一个特殊情况。
我正在尝试搜索这样的xml文件中的节点:
     <?xml version="1.0" encoding="utf-8" ?>
     <ConfigurationSection>
      <Configuration xmlns="clr-namespace:Newproject.Framework.Server.Store.Configuration;assembly=Newproject.Framework.Server" >
       <Configuration.Store>SqlServer</Configuration.Store>
       <Configuration.Engine>Staging</Configuration.Engine>
      </Configuration>
   </ConfigurationSection>

当我执行一个
xml = File.new(webconfig,"r")
doc = Nokogiri::XML(xml.read)
nodes = doc.search("//Configuration.Store")
xml.close

我得到了空节点。我错过了什么吗?我尝试过:
 nodes = doc.search("//Configuration\.Store")

仍然没有运气。

更新:我已经附上了整个xml文件。

再次更新xml:我的错误,它确实有一个命名空间。


1
猜测一下:XML文件中是否有命名空间? - choroba
@choroba 我已经附上整个xml文件,看起来没有命名空间。 - icn
使用 Ruby 1.9 和 Nokogiri 1.5.0 对我来说可行。(另外,请注意,在字符串中的单个反斜杠将转义字符串中的下一个字符;如果您想要一个带有文字反斜杠的字符串,您需要 "//Configuration\\.Store"。但是这不是必需的,因为您发布的内容没有任何转义就可以正常工作。) - Phrogz
我也可以(Ruby 1.8.7)。 - Wayne
更新了 XML。再次更正:我的错误,它确实有一个命名空间。 - icn
2个回答

5

编辑 #2:解决方案现在包括#parse_with_namespace

Nokogiri::XML::Node文档中,你可以找到许多与命名空间相关的Nokogiri方法。

# encoding: UTF-8
require 'rspec'
require 'nokogiri'

XML = <<XML
<?xml version="1.0" encoding="utf-8" ?>
  <ConfigurationSection>
   <Configuration xmlns="clr-namespace:Newproject.Framework.Server.Store.Configuration;assembly=Newproject.Framework.Server" >
    <Configuration.Store>SqlServer</Configuration.Store>
    <Configuration.Engine>Staging</Configuration.Engine>
   </Configuration>
</ConfigurationSection>
XML


class ConfigParser
  def parse(xml)
    doc = Nokogiri::XML(xml).remove_namespaces!
    configuration = doc.at('/ConfigurationSection/Configuration')
    store   = configuration.at("./Configuration.Store").text
    engine  = configuration.at("./Configuration.Engine").text
    {store: store, engine: engine}
  end

  def parse_with_namespace(xml)
    doc = Nokogiri::XML(xml)
    configuration = doc.at('/ConfigurationSection/xmlns:Configuration', 'xmlns' => 'clr-namespace:Newproject.Framework.Server.Store.Configuration;assembly=Newproject.Framework.Server')
    store   = configuration.at("./xmlns:Configuration.Store", 'xmlns' => 'clr-namespace:Newproject.Framework.Server.Store.Configuration;assembly=Newproject.Framework.Server').text
    engine  = configuration.at("./xmlns:Configuration.Engine", 'xmlns' => 'clr-namespace:Newproject.Framework.Server.Store.Configuration;assembly=Newproject.Framework.Server').text
    {store: store, engine: engine}
  end
end

describe ConfigParser do
  before(:each) do
    @parsed         = subject.parse XML
    @parsed_with_ns = subject.parse_with_namespace XML
  end

  it "should be able to parse the Configuration Store" do
    @parsed[:store].should eq "SqlServer"
  end

  it "should be able to parse the Configuration Engine" do
    @parsed[:engine].should eq "Staging"
  end

  it "should be able to parse the Configuration Store with namespace" do
    @parsed_with_ns[:store].should eq "SqlServer"
  end

  it "should be able to parse the Configuration Engine with namespace" do
    @parsed_with_ns[:engine].should eq "Staging"
  end
end

已更新XML。再次更正:我的错误,它确实具有名称空间。 - icn
有没有办法保留xmlns信息?我只想进行小调整并将其保存回去。 - icn
更新了一个新方法,保留命名空间。 - ezkl

0
require 'nokogiri'
XML = "<Configuration>
  <Configuration.Store>SqlServer</Configuration.Store>
  <Configuration.Engine>Staging</Configuration.Engine>
</Configuration>"
p Nokogiri::VERSION, Nokogiri.XML(XML).search('//Configuration.Store')
#=> "1.5.0"
#=> [#<Nokogiri::XML::Element:0x8103f0f8 name="Configuration.Store" children=[#<Nokogiri::XML::Text:0x81037524 "SqlServer">]>]

p RUBY_DESCRIPTION
#=> "ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.7.0]"

更新了 XML。再次更正,它确实有一个命名空间。 - icn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接