简体   繁体   中英

How do I validate specific attributes in XML using Ruby's REXML?

I'm trying to read some XML I've retrieved from a web service, and validate a specific attribute within the XML.

This is the XML up to the tag that I need to validate:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <QueryResponse xmlns="http://tempuri.org/">
      <QueryResult xmlns:a="http://schemas.datacontract.org/2004/07/Entity"
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:Navigation i:nil="true" />
        <a:SearchResult>
          <a:EntityList>
            <a:BaseEntity i:type="a:Product">
              <a:ExtractDateTime>1290398428</a:ExtractDateTime>
              <a:ExtractDateTimeFormatted>11/22/2010
              04:00:28</a:ExtractDateTimeFormatted>

Here's the code I have thus far using REXML in Ruby:

require 'xmlsimple'
require 'rexml/document'
require 'rexml/streamlistener'
include REXML


class Listener
include StreamListener

xmlfile = File.new("rbxml_CS_Query.xml")
xmldoc = Document.new(xmlfile)

# Now get the root element
root = xmldoc.root
puts root.attributes["a:EntityList"]

# This will output the date/time of the query response
xmldoc.elements.each("a:BaseEntity"){
   |e| puts e.attributes["a:ExtractDateTimeFormatted"]
}

end

I need to validate that ExtractDateTimeFormatted is there and has a valid value for that attribute. Any help is greatly appreciated. :)


Reading from local xml file.

File.open('temp.xml', 'w') { |f|
    f.puts request
    f.close
  }

  xml = File.read('temp.xml')

  doc = Nokogiri::XML::Reader(xml)
  extract_date_time_formatted = doc.at(
    '//a:ExtractDateTimeFormatted',
    'a' => 'http://schemas.datacontract.org/2004/07/Entity'
  ).inner_text
  show = DateTime.strptime(extract_date_time_formatted, '%m/%d/%Y')
  puts show

When I run this code I get an error: "undefined method 'at' for # on line 21

Are you tied to REXML or can you switch to Nokogiri ? I highly recommend Nokogiri over the other Ruby XML parsers.

I had to add enough XML tags to make the sample validate.

require 'date'
require 'nokogiri'

xml = %q{<?xml version="1.0"?>
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
      <s:Body>
          <QueryResponse xmlns="http://tempuri.org/">
              <QueryResult xmlns:a="http://schemas.datacontract.org/2004/07/Entity" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                  <a:Navigation i:nil="true"/>
                  <a:SearchResult>
                      <a:EntityList>
                          <a:BaseEntity i:type="a:Product">
                              <a:ExtractDateTime>1290398428</a:ExtractDateTime>
                              <a:ExtractDateTimeFormatted>11/22/2010</a:ExtractDateTimeFormatted>
                          </a:BaseEntity>
                      </a:EntityList>
                  </a:SearchResult>
              </QueryResult>
          </QueryResponse>
      </s:Body>
  </s:Envelope>
}

doc = Nokogiri::XML(xml)

extract_date_time_formatted = doc.at(
  '//a:ExtractDateTimeFormatted', 
  'a' => 'http://schemas.datacontract.org/2004/07/Entity'
).inner_text
puts DateTime.strptime(extract_date_time_formatted, '%m/%d/%Y') 
# >> 2010-11-22T00:00:00+00:00

There's a couple things going on that could make this harder to handle than a simple XML file.

  1. The XML is using namespaces. They are useful, but you have to tell the parser how to handle them. That is why I had to add the second parameter to the at() accessor.
  2. The date value is in a format that is often ambiguous. For many days of the year it is hard to tell whether it is mm/dd/yyyy or dd/mm/yyyy. Here in the US we assume it's the first, but Europe is the second. The DateTime parser tries to figure it out but often gets it wrong, especially when it thinks it's supposed to be dealing with a month 22. So, rather than let it guess, I told it to use mm/dd/yyyy format. If a date doesn't match that format, or the date's values are out of range Ruby will raise an exception, so you'll need to code for that.

This is an example of how to retrieve and parse XML on the fly:

require 'nokogiri'
require 'open-uri'

doc = Nokogiri::XML(open('http://java.sun.com/developer/earlyAccess/xml/examples/samples/book-order.xml'))
puts doc.class
puts doc.to_xml

And an example of how to read a local XML file and parse it:

require 'nokogiri'

doc = Nokogiri::XML(File.read('test.xml'))
puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <root xmlns:foo="bar">
# >>   <bar xmlns:hello="world"/>
# >> </root>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM