Permalink
Browse files

Implemented first pass of automatic namespace support.

Removed :use_default_namespace option.
  • Loading branch information...
1 parent e37ca5a commit a434992e149c6ad4e8a6948018457075aedb1172 @jnunemaker committed Jan 29, 2009
Showing with 281 additions and 136 deletions.
  1. +20 −18 lib/happymapper.rb
  2. +3 −3 lib/happymapper/item.rb
  3. +0 −31 lib/libxml_ext/libxml_helper.rb
  4. +170 −31 spec/fixtures/multiple_namespaces.xml
  5. +88 −53 spec/happymapper_spec.rb
View
@@ -62,36 +62,38 @@ def get_tag_name
def parse(xml, o={})
options = {
:single => false,
- :use_default_namespace => false,
+ :from_root => false,
}.merge(o)
-
- namespace = "default_ns:" if options[:use_default_namespace]
- doc = xml.is_a?(LibXML::XML::Node) ? xml : xml.to_libxml_doc
-
- nodes = if namespace
- node = doc.respond_to?(:root) ? doc.root : doc
- node.register_default_namespace(namespace.chop)
- node.find("#{namespace}#{get_tag_name}")
- else
- doc.find("//#{get_tag_name}")
+
+ doc = xml.is_a?(LibXML::XML::Node) ? xml : xml.to_libxml_doc
+ node = doc.respond_to?(:root) ? doc.root : doc
+
+ # if doc has a default namespace, turn on ':use_default_namespace' & set default_prefix for LibXML
+ unless node.namespaces.default.nil?
+ options[:use_default_namespace] = true
+ namespace = "default_ns:"
+ node.namespaces.default_prefix = namespace.chop
+ warn "Default XML namespace present -- results are unpredictable"
+ end
+
+ # if not using default namespace, get our namespace prefix (if we have one) (thanks to LibXML)
+ if node.namespaces.to_a.size > 0 && namespace.nil? && !node.namespaces.namespace.nil?
+ namespace = node.namespaces.namespace.prefix + ":"
end
nodes = if namespace
node = doc.respond_to?(:root) ? doc.root : doc
- node.register_default_namespace(namespace.chop)
- node.find("#{namespace}#{get_tag_name}")
+ node.find("#{'/' if options[:from_root]}#{namespace}#{get_tag_name}")
else
- nested = '.' unless doc.respond_to?(:root)
- path = "#{nested}//#{get_tag_name}"
- doc.find(path)
+ doc.find("//#{get_tag_name}")
end
collection = create_collection(nodes, namespace)
-
+
# per http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Document.html#M000354
nodes = nil
GC.start
-
+
options[:single] ? collection.first : collection
end
View
@@ -25,8 +25,8 @@ def from_xml_node(node, namespace = nil)
typecast(value_before_type_cast)
end
else
- use_default_namespace = !namespace.nil?
- type.parse(node, options.merge(:use_default_namespace => use_default_namespace))
+ # use_default_namespace = !namespace.nil?
+ type.parse(node, options)
end
end
@@ -74,7 +74,7 @@ def typecast(value)
private
def value_from_xml_node(node, namespace=nil)
- node.register_default_namespace(namespace.chop) if namespace
+ # node.register_default_namespace(namespace.chop) if namespace
if element?
depth = options[:deep] ? './/' : ''
@@ -51,37 +51,6 @@ def to_xml
def xpath
self.path
end
-
- # provide a name for the default namespace
- def register_default_namespace(name)
- default_namespace = namespaces.default
-
- if default_namespace
- register_namespace("#{name}:#{default_namespace.href}")
- else
- raise "No default namespace found"
- end
- end
-
- # register a namespace, of the form "foo:http://example.com/ns"
- def register_namespace(name_and_href)
- (@default_namespaces ||= []) << name_and_href
- end
-
- def find_with_default_ns(xpath_expr, namespace=nil)
- find_base(xpath_expr, namespace || default_namespaces)
- end
-
- def find_first_with_default_ns(xpath_expr, namespace=nil)
- find_first_base(xpath_expr, namespace || default_namespaces)
- end
-
-
- alias_method :find_base, :find unless method_defined?(:find_base)
- alias_method :find, :find_with_default_ns
-
- alias_method :find_first_base, :find_first unless method_defined?(:find_first_base)
- alias_method :find_first, :find_first_with_default_ns
end
class String
@@ -1,31 +1,170 @@
-<?xml version='1.0'?>
-<feed xmlns:ga="http://bigco.com" xmlns:opensearch="http://bigco.com">
- <opensearch:totalresults>4</opensearch:totalresults>
- <opensearch:startindex>1</opensearch:startindex>
- <opensearch:itemsperpage>4</opensearch:itemsperpage>
- <entry>
- <ga:accountid>12345</ga:accountid>
- <ga:accountname>Pride and Prejudice</ga:accountname>
- <ga:profileid>4321</ga:profileid>
- <ga:webpropertyid>UA-12345-1</ga:webpropertyid>
- <ga:tableid>ga:4321</ga:tableid> </entry>
- <entry>
- <ga:accountid>12345</ga:accountid>
- <ga:accountname>Pride and Prejudice</ga:accountname>
- <ga:profileid>5555</ga:profileid>
- <ga:webpropertyid>UA-12345-2</ga:webpropertyid>
- <ga:tableid>ga:5555</ga:tableid> </entry>
- <entry>
- <ga:accountid>54321</ga:accountid>
- <ga:accountname>Jane Austen</ga:accountname>
- <ga:profileid>2222</ga:profileid>
- <ga:webpropertyid>UA-54321-1</ga:webpropertyid>
- <ga:tableid>ga:2222</ga:tableid> </entry>
- <entry>
- <ga:accountid>54321</ga:accountid>
- <ga:accountname>Jane Austen</ga:accountname>
- <ga:profileid>3333</ga:profileid>
- <ga:webpropertyid>UA-54321-2</ga:webpropertyid>
- <ga:tableid>ga:3333</ga:tableid>
- </entry>
-</feed>
+<?xml version='1.0' encoding='UTF-8'?>
+<v2:TrackReply xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:v2='http://fedex.com/ws/track/v2'>
+ <v2:HighestSeverity>SUCCESS</v2:HighestSeverity>
+ <v2:Notifications>
+ <v2:Severity>SUCCESS</v2:Severity>
+ <v2:Source>trck</v2:Source>
+ <v2:Code>0</v2:Code>
+ <v2:Message>Request was successfully processed.</v2:Message>
+ <v2:LocalizedMessage>Request was successfully processed.</v2:LocalizedMessage>
+ </v2:Notifications>
+ <ns:TransactionDetail xmlns:ns='http://fedex.com/ws/track/v2'>
+<ns:CustomerTransactionId>20090102-111321</ns:CustomerTransactionId>
+</ns:TransactionDetail>
+ <ns:Version xmlns:ns='http://fedex.com/ws/track/v2'>
+<ns:ServiceId>trck</ns:ServiceId>
+<ns:Major>2</ns:Major>
+<ns:Intermediate>0</ns:Intermediate>
+<ns:Minor>0</ns:Minor>
+</ns:Version>
+ <v2:DuplicateWaybill>false</v2:DuplicateWaybill>
+ <v2:MoreData>false</v2:MoreData>
+ <v2:TrackDetails>
+ <v2:TrackingNumber>9611018034267800045212</v2:TrackingNumber>
+ <v2:TrackingNumberUniqueIdentifier>120081227094248461000~034267800045212</v2:TrackingNumberUniqueIdentifier>
+ <v2:StatusCode>OD</v2:StatusCode>
+ <v2:StatusDescription>On FedEx vehicle for delivery</v2:StatusDescription>
+ <v2:CarrierCode>FDXG</v2:CarrierCode>
+ <v2:ServiceInfo>Ground-Package Returns Program-Domestic</v2:ServiceInfo>
+ <v2:PackageWeight>
+ <v2:Units>LB</v2:Units>
+ <v2:Value>2.6</v2:Value>
+ </v2:PackageWeight>
+ <v2:Packaging>Package</v2:Packaging>
+ <v2:PackageSequenceNumber>1</v2:PackageSequenceNumber>
+ <v2:PackageCount>1</v2:PackageCount>
+ <v2:OriginLocationAddress>
+ <v2:City>SANFORD</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:OriginLocationAddress>
+ <v2:ShipTimestamp>2008-12-29T00:00:00</v2:ShipTimestamp>
+ <v2:EstimatedDeliveryTimestamp>2009-01-02T00:00:00</v2:EstimatedDeliveryTimestamp>
+ <v2:SignatureProofOfDeliveryAvailable>false</v2:SignatureProofOfDeliveryAvailable>
+ <v2:ProofOfDeliveryNotificationsAvailable>true</v2:ProofOfDeliveryNotificationsAvailable>
+ <v2:ExceptionNotificationsAvailable>true</v2:ExceptionNotificationsAvailable>
+ <v2:Events>
+ <v2:Timestamp>2009-01-02T06:00:00</v2:Timestamp>
+ <v2:EventType>OD</v2:EventType>
+ <v2:EventDescription>On FedEx vehicle for delivery</v2:EventDescription>
+ <v2:Address>
+ <v2:City>WICHITA</v2:City>
+ <v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
+ <v2:PostalCode>67226</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2009-01-02T01:17:32</v2:Timestamp>
+ <v2:EventType>AR</v2:EventType>
+ <v2:EventDescription>At local FedEx facility</v2:EventDescription>
+ <v2:Address>
+ <v2:City>WICHITA</v2:City>
+ <v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
+ <v2:PostalCode>67226</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2009-01-01T21:49:49</v2:Timestamp>
+ <v2:EventType>DP</v2:EventType>
+ <v2:EventDescription>Departed FedEx location</v2:EventDescription>
+ <v2:Address>
+ <v2:City>LENEXA</v2:City>
+ <v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
+ <v2:PostalCode>66227</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-31T16:19:00</v2:Timestamp>
+ <v2:EventType>AR</v2:EventType>
+ <v2:EventDescription>Arrived at FedEx location</v2:EventDescription>
+ <v2:Address>
+ <v2:City>LENEXA</v2:City>
+ <v2:StateOrProvinceCode>KS</v2:StateOrProvinceCode>
+ <v2:PostalCode>66227</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-30T11:01:23</v2:Timestamp>
+ <v2:EventType>DP</v2:EventType>
+ <v2:EventDescription>Departed FedEx location</v2:EventDescription>
+ <v2:Address>
+ <v2:City>ORLANDO</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:PostalCode>32809</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-30T05:00:00</v2:Timestamp>
+ <v2:EventType>AR</v2:EventType>
+ <v2:EventDescription>Arrived at FedEx location</v2:EventDescription>
+ <v2:Address>
+ <v2:City>ORLANDO</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:PostalCode>32809</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-30T03:16:33</v2:Timestamp>
+ <v2:EventType>DP</v2:EventType>
+ <v2:EventDescription>Left FedEx origin facility</v2:EventDescription>
+ <v2:Address>
+ <v2:City>SANFORD</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:PostalCode>32771</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-29T22:46:00</v2:Timestamp>
+ <v2:EventType>AR</v2:EventType>
+ <v2:EventDescription>Arrived at FedEx location</v2:EventDescription>
+ <v2:Address>
+ <v2:City>SANFORD</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:PostalCode>32771</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-29T17:12:00</v2:Timestamp>
+ <v2:EventType>PU</v2:EventType>
+ <v2:EventDescription>Picked up</v2:EventDescription>
+ <v2:Address>
+ <v2:City>SANFORD</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:PostalCode>32771</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ <v2:Events>
+ <v2:Timestamp>2008-12-27T09:40:00</v2:Timestamp>
+ <v2:EventType>IP</v2:EventType>
+ <v2:EventDescription>In FedEx possession</v2:EventDescription>
+ <v2:StatusExceptionCode>084</v2:StatusExceptionCode>
+ <v2:StatusExceptionDescription>Tendered at FedEx location</v2:StatusExceptionDescription>
+ <v2:Address>
+ <v2:City>LONGWOOD</v2:City>
+ <v2:StateOrProvinceCode>FL</v2:StateOrProvinceCode>
+ <v2:PostalCode>327506398</v2:PostalCode>
+ <v2:CountryCode>US</v2:CountryCode>
+ <v2:Residential>false</v2:Residential>
+ </v2:Address>
+ </v2:Events>
+ </v2:TrackDetails>
+</v2:TrackReply>
Oops, something went wrong.

1 comment on commit a434992

Contributor

mojodna commented on a434992 Jan 29, 2009

I also re-fixed this last night (based on the patch I sent a while back before libxml was upgraded). It eliminates the need for :use_default_namespace, for if one is present, all queries w/o a namespace must be (transparently) modified to use one.

It also allows mapping multiple elements to a single object that have multiple namespaces associated with them.

The branch is here:
http://github.com/mojodna/happymapper/tree/namespaces

Please sign in to comment.