indexing description: "XML document extracting tools" license: "MIT license (see ../license.txt)" author: "Beat Strasser " date: "$Date$" revision: "$Revision$" class P2P_XML_DOCUMENT_CREATOR create make feature {NONE} -- Initialization make is -- Create XML document creator ;) do create custom_advertisement_creators.make_default end feature -- Element change extend_custom_creator (a_root_name: STRING; a_creator: FUNCTION [ANY, TUPLE [XM_ELEMENT], P2P_XML_CACHE]) is -- Register `a_creator' for advertisements with root `a_root_name' require Name_valid: a_root_name /= Void and not a_root_name.is_empty Creator_valid: a_creator /= Void do custom_advertisement_creators.force (a_creator, a_root_name) end prune_custom_creator (a_root_name: STRING) is -- Unregister creator for advertisements with root `a_root_name' require Name_valid: a_root_name /= Void do custom_advertisement_creators.remove (a_root_name) end prune_all_custom_creators is -- Unregister all custom creators do custom_advertisement_creators.wipe_out end feature -- Basic operations document_from_element (an_element: XM_ELEMENT): P2P_XML_CACHE is -- Extract a document from an XML tree with root `an_element'. -- Return Void if creation of an object was not successful. require Root_valid: an_element /= Void local attr: XM_ATTRIBUTE children: DS_LIST [XM_ELEMENT] child: XM_ELEMENT do -- detect type by element's name Result := create_specific_type (an_element.name, an_element) if Result = Void then -- detect type by element's attribute `type' attr := an_element.attribute_by_name ("type") if attr /= Void then Result := create_specific_type (strip_namespace (attr.value), an_element) end end children := an_element.elements if Result = Void and children.count = 1 then -- detect type by element's single child name child := children.first Result := create_specific_type (child.name, child) if Result = Void then -- detect type by element's single child attribute `type' attr := child.attribute_by_name ("type") if attr /= Void then Result := create_specific_type (strip_namespace (attr.value), child) end end end if Result = Void then -- create a general xml document create {P2P_UNKNOWN_XML_DOCUMENT} Result.make_from_element (an_element) end -- check for valid document if not Result.is_valid then Result := Void end end advertisement_from_element (an_element: XM_ELEMENT): P2P_ADVERTISEMENT is -- Try to extract a document from an XML tree with root `an_element'. -- Return either Void when not a valid advertisement, an unknown advertisement when -- the type is unknown, or a real advertisement on successful advertisement detection. require Root_valid: an_element /= Void local document: P2P_XML_CACHE unknown: P2P_UNKNOWN_XML_DOCUMENT do document := document_from_element (an_element) if document /= Void then Result ?= document if Result = Void then unknown ?= document if unknown /= Void then create {P2P_UNKNOWN_ADVERTISEMENT} Result.make_from_document (unknown) end end end end feature -- Access Rootname_peer: STRING is "PA" Rootname_group: STRING is "PGA" Rootname_module_class: STRING is "MCA" Rootname_module_specification: STRING is "MSA" Rootname_module_implementation: STRING is "MIA" Rootname_pipe: STRING is "PipeAdvertisement" Rootname_transport_tcp: STRING is "TCPTransportConfiguration" Rootname_platform_config: STRING is "CP" Rootname_route: STRING is "RA" Rootname_accesspoint: STRING is "APA" Rootname_rendezvous: STRING is "RdvAdvertisement" Rootname_rendezvous_propagate: STRING is "RendezVousPropagateMessage" Rootname_rendezvous_configuration: STRING is "RdvConfig" Rootname_resolver_query: STRING is "ResolverQuery" Rootname_resolver_response: STRING is "ResolverResponse" Rootname_resolver_srdi: STRING is "ResolverSRDI" Rootname_discovery_query: STRING is "DiscoveryQuery" Rootname_discovery_response: STRING is "DiscoveryResponse" feature {NONE} -- Implementation custom_advertisement_creators: DS_HASH_TABLE [FUNCTION [ANY, TUPLE [XM_ELEMENT], P2P_XML_CACHE], STRING] create_specific_type (a_name: STRING; an_element: XM_ELEMENT): P2P_XML_CACHE is -- Detect specific type from `a_name' and create the corresponding document with root `an_element' require Name_valid: a_name /= Void Root_element_valid: an_element /= Void local creator: FUNCTION [ANY, TUPLE [XM_ELEMENT], P2P_XML_CACHE] do -- custom advertisements (higher priority than standard advertisements) if custom_advertisement_creators.has (a_name) then -- call responsible creator for `a_name' creator := custom_advertisement_creators.item (a_name) creator.call ([an_element.deep_twin]) Result := creator.last_result -- advertisements elseif rootname_peer.is_equal (a_name) then create {P2P_PEER_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_group.is_equal (a_name) then create {P2P_PEERGROUP_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_module_class.is_equal (a_name) then create {P2P_MODULE_CLASS_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_module_specification.is_equal (a_name) then create {P2P_MODULE_SPECIFICATION_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_module_implementation.is_equal (a_name) then create {P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_pipe.is_equal (a_name) then create {P2P_PIPE_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_transport_tcp.is_equal (a_name) then create {P2P_TCP_CONFIGURATION} Result.make_from_element (an_element.deep_twin) elseif rootname_route.is_equal (a_name) then create {P2P_ROUTE_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_accesspoint.is_equal (a_name) then create {P2P_ACCESSPOINT_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) elseif rootname_rendezvous.is_equal (a_name) then create {P2P_RENDEZVOUS_ADVERTISEMENT} Result.make_from_element (an_element.deep_twin) -- other xml documents elseif rootname_platform_config.is_equal (a_name) then create {P2P_CONFIGURATION} Result.make_from_element (an_element.deep_twin) elseif rootname_rendezvous_propagate.is_equal (a_name) then create {P2P_RENDEZVOUS_PROPAGATE} Result.make_from_element (an_element.deep_twin) elseif rootname_rendezvous_configuration.is_equal (a_name) then create {P2P_RENDEZVOUS_CONFIGURATION} Result.make_from_element (an_element.deep_twin) elseif rootname_resolver_query.is_equal (a_name) then create {P2P_RESOLVER_QUERY} Result.make_from_element (an_element.deep_twin) elseif rootname_resolver_response.is_equal (a_name) then create {P2P_RESOLVER_RESPONSE} Result.make_from_element (an_element.deep_twin) elseif rootname_resolver_srdi.is_equal (a_name) then create {P2P_RESOLVER_SRDI} Result.make_from_element (an_element.deep_twin) elseif rootname_discovery_query.is_equal (a_name) then create {P2P_DISCOVERY_QUERY} Result.make_from_element (an_element.deep_twin) elseif rootname_discovery_response.is_equal (a_name) then create {P2P_DISCOVERY_RESPONSE} Result.make_from_element (an_element.deep_twin) end end strip_namespace (a_value: STRING): STRING is -- Return a string equal to `a_value', but without namespace require Value_valid: a_value /= Void do Result := a_value.twin if Result.substring (1, 5).is_equal ("jxta:") then Result.remove_head (5) end ensure Result_set: Result /= Void and Result /= a_value end end