XML文件中的Ruby nokogiri属性选择器

时间:2019-03-08 14:17:13

标签: ruby nokogiri

这是xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
    <SOAP-ENV:Body>
        <ns1:putResponse
            xmlns:ns1="urn:DmsManagerClient">
            <result xsi:type="xsd:string">
                <?xml version="1.0" encoding="ISO-8859-1"?>
                <MESSAGE ID="11c73b9e-687c-4300-baba-b743c26f7c83" TYPE="CUSDMS">
                    <DELIVERY>
                        <FROM>
                            <SENDER>0072000</SENDER>
                            <SERVICE>eService</SERVICE>
                            <DATE>2019-03-08T12:27:25</DATE>
                        </FROM>
                        <TO>
                            <DEALER DEALERCODE="0072000" MARKETCODE="1000"/>
                        </TO>
                    </DELIVERY>
                    <CONTENT>
                        <dms:ComplexResponse ErrorCode="430" ErrorDescription="null :  PrivacyUE Mancante" Return="false"
                            xmlns:dms="http://dmsmanagerservice">
                            <dms:Element Name="DMSVERSION">2.7</dms:Element>
                        </dms:ComplexResponse>
                    </CONTENT>
                </MESSAGE>
            </result>
        </ns1:putResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我正在使用Ruby进行编码,并且我使用了Nokogiri和xpath方法来扩展文件的“内容”

这是代码:

def extrapolate_error(xml)
  doc = Nokogiri::XML(File.open(xml))
  doc.xpath('//CONTENT')

end

这是结果:

[#<Nokogiri::XML::Element:0x1c5ba78 name="CONTENT" children=[
   #<Nokogiri::XML::Text:0x1c5b940 "\n">, 
   #<Nokogiri::XML::Element:0x1c5b8bc name="ComplexResponse" namespace=#<Nokogiri::XML::Namespace:0x1c5b88c prefix="dms" href="http://dmsmanagerservice"> 
     attributes=[
       #<Nokogiri::XML::Attr:0x1c5b874 name="ErrorCode" value="430">, 
       #<Nokogiri::XML::Attr:0x1c5b868 name="ErrorDescription" value="null :  PrivacyUE Mancante">, 
       #<Nokogiri::XML::Attr:0x1c5b85c name="Return" value="false">] 
       children=[#<Nokogiri::XML::Text:0x1c5b118 "\n">, 
                 #<Nokogiri::XML::Element:0x1c5b094 name="Element" namespace=#<Nokogiri::XML::Namespace:0x1c5b88c prefix="dms" href="http://dmsmanagerservice"> 
             attributes=[#<Nokogiri::XML::Attr:0x1c5b058 name="Name" value="DMSVERSION">] 
             children=[#<Nokogiri::XML::Text:0x1c5abe4 "2.7">]>, 
                     #<Nokogiri::XML::Text:0x1c5aaac "\n">]>,
                     #<Nokogiri::XML::Text:0x1c5a974 "\n">]>]

现在我需要输入它并选择一些属性。

具体来说,我需要这个:

name =“ ErrorCode”值=“ 430”

name =“ ErrorDescription” value =“ null:PrivacyUE Mancante”

我不知道如何进行。你能帮我吗?

1 个答案:

答案 0 :(得分:1)

假设dms名称空间始终相同,以下内容将为您工作

doc.xpath('//CONTENT/dms:ComplexResponse', dms: 'http://dmsmanagerservice')
    .xpath('@ErrorCode | @ErrorDescription')
    .each_with_object({}) do |e,obj| 
      obj[e.name] = e.text
    end
#=> {"ErrorCode"=>"430", "ErrorDescription"=>"null :  PrivacyUE Mancante"}

您已经了解了如何// CONTENT,因此从那里我们使用dms:ComplexResponse进行更深入的导航,但是由于这是命名空间,因此我们必须提供命名空间引用,例如dms: 'http://dmsmanagerservice'

然后,我们选择对@ErrorCode@ErrorDescription感兴趣的属性。

XPath中,管道|表示UNION(认为AND),因此我们要选择两者。

然后,我们仅使用Hash作为键并使用name作为值来构建text

XPath Cheatsheet-有用的资源,如果您需要其他参考

更新

您询问有条件的东西,所以这就是我的建议

ndoc = Nokogiri::XML(doc)
namespaces = ndoc.collect_namespaces

response = ndoc.xpath("//CONTENT/dms:ComplexResponse", namespaces)

if response.xpath("self::node()[@ErrorCode != '' and @ErrorDescription != '']").any?
  response.xpath("@ErrorCode | @ErrorDescription")
  .each_with_object({}) do |e,obj| 
    obj[e.name] = e.text
  end
else
  response.xpath('dms:Element/@Name | dms:Element/text()',namespaces)
    .each_slice(2)
    .map {|s| s.map(&:text)}.to_h
end

这将检查是否存在一个ErrorCode和一个ErrorDescription(如果存在),然后按最初建议的方式进行哈希处理。如果不是,那么它将所有dms:Elements作为Hash返回,因此{"DMSVERSION"=>"2.7"}在这种情况下为Functional Example