# -*- ruby -*- require 'xtemplate' require 'xtemplate/xpath' if( !(defined?(REXML) || defined?(XMLScan)) ) begin require 'xmlscan/parser' rescue LoadError begin require 'rexml/document' rescue LoadError raise(LoadError, "XTemplate can't find both of xmlscan and REXML.") end end end module XTemplate module XNodeManager attr_reader :root NEWLINE = $/ def init_root() @root = XNode.new(nil) end def push_tag(tag) node = XNode.new(SanitizedString.new(tag)) @root.add_child(node) @root = node end def push_attr(attr) @root.add_attr(attr) end def push_attrval(val) @root.add_attrval(SanitizedString[val]) end def push_content(*str) @root.add_child(SanitizedString[*str]) end def pop_node @root = @root.parent end def push_optname(str) @root.add_optname(str) end def push_optval(val) @root.add_optval(SanitizedString[val]) end def push_pi(target, pi) case target.downcase when "xtemplate" push_tag(nil) @root.pi = pi pop_node() else if( pi && pi.strip != "" ) push_content("") else push_content("") end end end def to_s @root.to_s end end if( defined?(XMLScan) ) class XMLVisitor include Util include XNodeManager def initialize init_root() #@orig_kcode = $KCODE end def set_parser(x) @parser = x end def parse_error(msg) raise(RuntimeError, "%s:%d:%s" % [@parser.path, @parser.lineno, msg]) end def wellformed_error(msg) raise(RuntimeError, "%s:%d:%s" % [@parser.path, @parser.lineno, msg]) end def valid_error(msg) raise(RuntimeError, "%s:%d:%s" % [@parser.path, @parser.lineno, msg]) end def warning(msg) end def on_xmldecl push_content("", NEWLINE) end def on_doctype(root,pubid,sysid) if( pubid ) if( sysid ) push_content("") else push_content("") end else if( sysid ) push_content("") else push_content("") end end push_content(NEWLINE) end def on_prolog_space(str) push_content(str) end def on_comment(str) push_content("") end def on_pi(target, pi) push_pi(target,pi) end def on_chardata(str) push_content(str) end def on_cdata(str) push_content("") end def on_entityref(ref) push_content("&#{ref};") end def on_charref(code) push_content("&\##{code};") end def on_charref_hex(code) push_content("&\#x#{'%x' % code};") end def on_start_document end def on_end_document #@root.add_child(NEWLINE) #$KCODE = @orig_kcode end def on_attribute(name) push_attr(name) end def on_attr_value(str) push_attrval(str) end def on_attr_entityref(ref) push_attrval("&#{ref};") end def on_attr_charref(code) push_attrval("&\##{code};") end def on_attr_charref_hex(code) push_attrval("&\#x#{'%x' % code};") end def on_attribute_end(name) end def on_stag(name) push_tag(name) end def on_stag_end_empty(name) on_stag_end(name) on_etag(name) end def on_stag_end(name) end def on_etag(name) pop_node() end end class XMLScanParser < XMLScan::XMLParser private def on_entityref(ref) @visitor.on_entityref ref end def on_attr_entityref(ref) @visitor.on_attr_entityref ref end end class XMLParser def initialize() @visitor = XMLVisitor.new @parser = XMLScanParser.new(@visitor) @visitor.set_parser(@parser) end def parse(doc) @parser.parse(doc) @visitor.root end end elsif( defined?(REXML) ) class XMLListener include XNodeManager def initialize init_root() end def tag_start(name, attrs) push_tag(name) attrs.each{|attr,val| push_attr(attr) push_attrval(val) } end def tag_end(name) pop_node() end def text(str) push_content(REXML::Text::normalize(str)) end def instruction(target, pi) push_pi(target, pi) end def comment(str) push_content("") end def doctype(root, pub_sys, long_name, uri) if( root && pub_sys && uri ) push_content("") elsif( root && pub_sys && !uri ) push_content("") elsif( root && !pubid && !uri ) push_content("") end push_content(NEWLINE) end def attlistdecl(content) push_content("") end def elementdecl(content) push_content("") end def entitydecl(contents) push_content("") end def notationdecl(content) push_content("") end def entity(s) push_content("%#{s};") end def cdata(s) push_content("") end def xmldecl(version, encoding, standalone) content = [] if( version ) content.push("version=\"#{version}\"") end if( encoding ) content.push("encoding=\"#{encoding}\"") end if( standalone ) content.push("standalone=\"#{standalone}\"") end push_content("", NEWLINE) end end class XMLParser def initialize @listener = XMLListener.new end def parse(io) REXML::Document.parse_stream(io, @listener) @listener.root end end end # REXML, XMLScan class XMLDocument include XPath def initialize(text) @hash = nil case text when XNode @node = text when Hash,Array @node = XNode.new() value_to_xml(text, @node) else @node = parse(text) @node.prepare(nil, {:@type => true, :include => true, :template => true}) end end def parse(text) XMLParser.new.parse(text) end def strip!(recursive=true) @node.strip!(recursive) end def to_hash() @node.to_hash() end def to_s() @node.to_s() end def [](path) root = to_hash() xpath(path,root) end end end