无法使用Nokogiri提取XML元素的值

时间:2013-06-14 18:34:47

标签: ruby nokogiri jrubyonrails

我正在尝试解析以下XML以使用Nokogiri XML解析器提取//ns2:Point/ns2:pos下的Lat Long组合,但没有太多运气。

<?xml version="1.0" encoding="UTF-8"?>
<ns1:XLS ns1:lang="en" rel="5.2.sp03" version="1.0" xmlns:ns1="http://www.opengis.net/xls">
    <ns1:ResponseHeader sessionID="wrx-rails1370997540"/>
    <ns1:Response numberOfResponses="1" requestID="10" version="1.0">
        <ns1:GeocodeResponse>
            <ns1:GeocodeResponseList numberOfGeocodedAddresses="1">
                <ns1:GeocodedAddress>
                    <ns2:Point xmlns:ns2="http://www.opengis.net/gml">
                        <ns2:pos>38.898331 -77.117273</ns2:pos>
                    </ns2:Point>
                    <ns1:Address countryCode="US">
                        <ns1:StreetAddress>
                            <ns1:Building number="4400"/>
                            <ns1:Street>Lee Hwy</ns1:Street>
                        </ns1:StreetAddress>
                        <ns1:Place type="CountrySubdivision">VA</ns1:Place>
                        <ns1:Place type="CountrySecondarySubdivision">Arlington</ns1:Place>
                        <ns1:Place type="MunicipalitySubdivision">Arlington</ns1:Place>
                        <ns1:PostalCode>22207</ns1:PostalCode>
                    </ns1:Address>
                    <ns1:GeocodeMatchCode accuracy="1.0" matchType="ADDRESS POINT LOOKUP"/>
                    <ns1:SpatialKeys>
                        <ns1:SpatialKey priority="0" val="1663355010"/>
                        <ns1:SpatialKey priority="1" val="2563322400"/>
                        <ns1:SpatialKey priority="2" val="3325185160"/>
                        <ns1:SpatialKey priority="3" val="3784086306"/>
                        <ns1:SpatialKey priority="4" val="4033029320"/>
                        <ns1:SpatialKey priority="5" val="4162373938"/>
                        <ns1:SpatialKey priority="6" val="4228264524"/>
                        <ns1:SpatialKey priority="7" val="4261514387"/>
                        <ns1:SpatialKey priority="8" val="4278215460"/>
                        <ns1:SpatialKey priority="9" val="4286585033"/>
                        <ns1:SpatialKey priority="10" val="4290774578"/>
                        <ns1:SpatialKey priority="11" val="4292870540"/>
                        <ns1:SpatialKey priority="12" val="4293918819"/>
                        <ns1:SpatialKey priority="13" val="4294443032"/>
                        <ns1:SpatialKey priority="14" val="4294705158"/>
                        <ns1:SpatialKey priority="15" val="4294836224"/>
                    </ns1:SpatialKeys>
                </ns1:GeocodedAddress>
            </ns1:GeocodeResponseList>
        </ns1:GeocodeResponse>
    </ns1:Response>
</ns1:XLS>

当我尝试以下操作时,我得到一个空数组:

doc = Nokogiri::XML(response.body);
pos = doc.xpath('//ns2:Point/ns2:pos');

我可以访问Geocoded地址元素但是很好用:

doc.xpath('//ns1:GeocodeResponseList/ns1:GeocodedAddress')

关于我在这里缺少什么的任何线索。它是由于某种原因而不喜欢的命名空间改变吗?

我的环境如下: Nokogiri 1.5.9 Java Rails 3.2.11 jRuby 1.7.4 Windows 7 Box

1 个答案:

答案 0 :(得分:0)

你可以找到第一个表达式,因为Nokogiri找到了它所期望的XML命名空间。 ns2命名空间不是我们通常找到的地方,因此Nokogiri不知道该怎么做。

有多种方法可以解决这个问题。第一种是在文档中收集命名空间,并在搜索时将它们传递给Nokogiri。 Nokogiri会自动为XML根目录中的命名空间执行此操作,但如果它们遍布整个文档,则不会这样做,因此我们必须告诉它在任何地方进行搜索,然后将其传递到:

namespaces = doc.collect_namespaces
namespaces # => {"xmlns:ns1"=>"http://www.opengis.net/xls", "xmlns:ns2"=>"http://www.opengis.net/gml"}
pos = doc.xpath('//ns2:Point/ns2:pos', namespaces);
pos # => [#<Nokogiri::XML::Element:0x3fe8c608ab30 name="pos" namespace=#<Nokogiri::XML::Namespace:0x3fe8c608aacc prefix="ns2" href="http://www.opengis.net/gml"> children=[#<Nokogiri::XML::Text:0x3fe8c608e1b8 "38.898331 -77.117273">]>]

另一种方法是告诉Nokogiri从文档中删除所有名称空间。如果您确定在文档中的各个名称空间中找到的标记名称之间没有冲突,您只想这样做:

doc.remove_namespaces!
pos = doc.xpath('//Point/pos', namespaces);
pos # => [#<Nokogiri::XML::Element:0x3fe8c608ab30 name="pos" children=[#<Nokogiri::XML::Text:0x3fe8c608e1b8 "38.898331 -77.117273">]>]

Nokogiri documentation可以说明remove_namespaces!的使用:

  

但我懒惰而且不想处理命名空间!

     

懒惰==高效,所以没有判断。 :)

     

如果你有一个带有命名空间的XML文档,但是更愿意完全忽略它们(并且查询就像Tim Bray从未发明过它们那样),那么你可以在XML :: Document上调用remove_namespaces来删除所有命名空间。当然,如果文档具有相同名称但名称空间不同的节点,则它们现在将是不明确的。但你很懒!你不在乎!