Análise genérica de XML em RubyMotion com NSXMLParser

Tenho trabalhado muito com objetos NSXMLParser retornados pelo AFMotion recentemente e não consegui descobrir muito sobre como usar seu estilo delegado de análise. Achei que deveria compartilhar o amor com este analisador genérico. Não leva em conta os namespaces ou qualquer coisa, mas esta é uma boa base simples se você precisar de uma.

class XMLParserDelegate
attr_reader
:root

def initialize
@root = nil
@queue = []
end

def parser(parser, didStartElement:elementName, namespaceURI:namespaceURI, qualifiedName:qualifiedName, attributes:attributeDict)
el
= XMLElement.new(elementName, attributeDict)

if @queue.empty?
@root = el
else
@queue[-1].add_child(el)
end

@queue << el
end

def parser(parser, didEndElement:elementName, namespaceURI:namespaceURI, qualifiedName:qName)
@queue.pop
end
end

class XMLElement
attr_accessor
:name, :attributes, :children

def initialize(name, attributes)
@el = name
@attributes = attributes
@children = []
end

def add_child(el)
@children << el
end

def to_xml
if @children.empty?
'<' + @el + attrs_as_xml + '/>'
else
'<' + @el + attrs_as_xml + '>' + @children.map(&:to_xml).join + '</' + @el + '>'
end
end

private

def attrs_as_xml
@attributes.map { |k, v| ' ' + k.to_s + '="' + v.to_s + '"' }.join
end
end

Usado assim (por exemplo no REPL):

(main)> AFMotion::XML.get('http://example.com/test.xml') do |result|
parser
= result.object
end

=> #<AFXMLRequestOperation:0xa0d6490>
(main)> parser.delegate = XMLParserDelegate.new
=> #<XMLParserDelegate:0xa0d8900 @root=nil @queue=[]>
(main)> parser.parse
=> 1
(main)> parser.delegate.root
=> #<XMLElement:....>

Existem muitos outros callbacks NSXMLParserDelegate para verificar, então dê uma olhada .