Class: XSD::XMLParser::LibXMLParser
- Defined in:
- lib/xsd/xmlparser/libxmlparser.rb
Instance Attribute Summary
Attributes inherited from Parser
Instance Method Summary collapse
-
#do_parse(string_or_readable) ⇒ Object
Parses via XML::Reader rather than the SaxParser callbacks used before.
Methods inherited from Parser
add_factory, create_parser, factory, #initialize, #parse
Constructor Details
This class inherits a constructor from XSD::XMLParser::Parser
Instance Method Details
#do_parse(string_or_readable) ⇒ Object
Parses via XML::Reader rather than the SaxParser callbacks used before. libxml-ruby's SAX2 callback (on_start_element_ns) never surfaces an attribute's own namespace prefix to Ruby: the C extension (ruby_xml_sax2_handler.c's start_element_ns_callback) only reads an attribute's local name and value, discarding the prefix/URI slots that libxml2 itself provides per attribute. That made it impossible to recognize namespace-qualified attributes such as xsi:type, xsi:nil, and xml:lang, which SOAP4R's demarshaller depends on to pick the right Ruby type -- values silently fell back to an untyped SOAP::Mapping::Object, or stayed raw strings instead of being cast to Integer/nil/etc. This gap is still present as of libxml-ruby 6.0.0 (2026); it isn't a matter of being on an old release.
XML::Reader's per-attribute #name does return the full "prefix:local" form (confirmed against libxml-ruby 2.8.0, the version pinned for Ruby 1.9.3, through the current 3.x/6.x releases) -- matching exactly what REXML's tag_start and Ox's attr callbacks already hand back, so this mirrors their convention rather than trying to resolve namespace URIs itself.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/xsd/xmlparser/libxmlparser.rb', line 35 def do_parse(string_or_readable) $stderr.puts "XSD::XMLParser::LibXMLParser.do_parse" if $DEBUG @charset = 'utf-8' string = string_or_readable.respond_to?(:read) ? string_or_readable.read : string_or_readable reader = ::LibXML::XML::Reader.string(string) while reader.read case reader.node_type when ::LibXML::XML::Reader::TYPE_ELEMENT name = reader.name attrs = read_attributes(reader) empty = reader.empty_element? start_element(name, attrs) end_element(name) if empty when ::LibXML::XML::Reader::TYPE_END_ELEMENT end_element(reader.name) when ::LibXML::XML::Reader::TYPE_TEXT, ::LibXML::XML::Reader::TYPE_CDATA, ::LibXML::XML::Reader::TYPE_SIGNIFICANT_WHITESPACE characters(reader.value) end end rescue ::LibXML::XML::Error => e raise ParseError.new(e.) end |