Module: Canon::XmlParsing
- Defined in:
- lib/canon/xml_parsing.rb
Overview
Backend-agnostic XML parsing, serialization, and type dispatch.
Provides a unified API that delegates to the active backend (Nokogiri or moxml/Oga). Uses backend-branching (‘if XmlBackend.nokogiri?`) rather than `case/when` with constant references — this ensures Nokogiri constants are never resolved under Opal, preventing NameError at runtime.
OCP: adding a new backend only requires updating this module. DRY: all backend dispatch centralized here, not scattered across comparator/formatter files.
Class Method Summary collapse
- .attribute_value(node, attr_name) ⇒ Object
- .attributes(node) ⇒ Object
- .canonicalize(node, options = {}) ⇒ Object
- .cdata?(node) ⇒ Boolean
-
.children(node) ⇒ Object
— Node traversal —.
- .comment?(node) ⇒ Boolean
-
.document?(obj) ⇒ Boolean
— Type checks (backend-safe) —.
- .document_fragment?(obj) ⇒ Boolean
- .dtd?(node) ⇒ Boolean
- .element?(node) ⇒ Boolean
- .moxml_context ⇒ Object
- .name(node) ⇒ Object
- .namespace_definitions(node) ⇒ Object
- .namespace_uri(node) ⇒ Object
-
.node_type(node) ⇒ Object
Returns a symbol for all backends (:element, :text, :comment, etc.) or nil for unrecognised nodes.
- .parent(node) ⇒ Object
-
.parse(xml_string, options = {}) ⇒ Object
— Parsing —.
- .parse_fragment(xml_string) ⇒ Object
- .processing_instruction?(node) ⇒ Boolean
-
.serialize(node) ⇒ Object
— Serialization —.
- .text_content(node) ⇒ Object
- .text_node?(node) ⇒ Boolean
- .xml_node?(obj) ⇒ Boolean
Class Method Details
.attribute_value(node, attr_name) ⇒ Object
169 170 171 172 173 174 175 |
# File 'lib/canon/xml_parsing.rb', line 169 def attribute_value(node, attr_name) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Element) ? node[attr_name.to_s] : nil else node.is_a?(Moxml::Element) ? node[attr_name.to_s] : nil end end |
.attributes(node) ⇒ Object
161 162 163 164 165 166 167 |
# File 'lib/canon/xml_parsing.rb', line 161 def attributes(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Element) ? node.attributes.values : [] else node.is_a?(Moxml::Element) ? node.attributes : [] end end |
.canonicalize(node, options = {}) ⇒ Object
211 212 213 214 215 216 217 |
# File 'lib/canon/xml_parsing.rb', line 211 def canonicalize(node, = {}) if XmlBackend.nokogiri? node.canonicalize() else moxml_canonicalize(node, ) end end |
.cdata?(node) ⇒ Boolean
96 97 98 99 100 101 102 |
# File 'lib/canon/xml_parsing.rb', line 96 def cdata?(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::CDATA) || node.is_a?(Moxml::Cdata) else node.is_a?(Moxml::Cdata) end end |
.children(node) ⇒ Object
— Node traversal —
130 131 132 133 134 135 136 |
# File 'lib/canon/xml_parsing.rb', line 130 def children(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Node) ? node.children.to_a : [] else node.is_a?(Moxml::Node) ? node.children.to_a : [] end end |
.comment?(node) ⇒ Boolean
88 89 90 91 92 93 94 |
# File 'lib/canon/xml_parsing.rb', line 88 def comment?(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Comment) || node.is_a?(Moxml::Comment) else node.is_a?(Moxml::Comment) end end |
.document?(obj) ⇒ Boolean
— Type checks (backend-safe) —
Both Nokogiri and Moxml are loaded as dependencies. XmlBackend determines which is used for parsing, but nodes from either library may flow through comparison code (e.g. tests, format detection). Under Nokogiri backend, both types are checked.
56 57 58 59 60 61 62 |
# File 'lib/canon/xml_parsing.rb', line 56 def document?(obj) if XmlBackend.nokogiri? obj.is_a?(Nokogiri::XML::Document) || obj.is_a?(Moxml::Document) else obj.is_a?(Moxml::Document) end end |
.document_fragment?(obj) ⇒ Boolean
112 113 114 115 116 117 118 |
# File 'lib/canon/xml_parsing.rb', line 112 def document_fragment?(obj) if XmlBackend.nokogiri? obj.is_a?(Nokogiri::XML::DocumentFragment) else false end end |
.dtd?(node) ⇒ Boolean
120 121 122 123 124 125 126 |
# File 'lib/canon/xml_parsing.rb', line 120 def dtd?(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::DTD) else false end end |
.element?(node) ⇒ Boolean
72 73 74 75 76 77 78 |
# File 'lib/canon/xml_parsing.rb', line 72 def element?(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Element) || node.is_a?(Moxml::Element) else node.is_a?(Moxml::Element) end end |
.moxml_context ⇒ Object
16 17 18 |
# File 'lib/canon/xml_parsing.rb', line 16 def moxml_context @moxml_context ||= Moxml.new(RUBY_ENGINE == "opal" ? :rexml : :oga) end |
.name(node) ⇒ Object
138 139 140 141 142 143 144 |
# File 'lib/canon/xml_parsing.rb', line 138 def name(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Node) ? node.name : nil else node.is_a?(Moxml::Node) ? node.name : nil end end |
.namespace_definitions(node) ⇒ Object
177 178 179 180 181 182 183 |
# File 'lib/canon/xml_parsing.rb', line 177 def namespace_definitions(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Element) ? node.namespace_definitions : [] else node.is_a?(Moxml::Element) ? node.namespace_definitions : [] end end |
.namespace_uri(node) ⇒ Object
193 194 195 196 197 198 199 |
# File 'lib/canon/xml_parsing.rb', line 193 def namespace_uri(node) if XmlBackend.nokogiri? node.namespace&.href if node.is_a?(Nokogiri::XML::Element) elsif node.is_a?(Moxml::Element) node.namespace_uri end end |
.node_type(node) ⇒ Object
Returns a symbol for all backends (:element, :text, :comment, etc.) or nil for unrecognised nodes.
203 204 205 206 207 208 209 |
# File 'lib/canon/xml_parsing.rb', line 203 def node_type(node) if XmlBackend.nokogiri? nokogiri_node_type(node) else moxml_node_type(node) end end |
.parent(node) ⇒ Object
185 186 187 188 189 190 191 |
# File 'lib/canon/xml_parsing.rb', line 185 def parent(node) return nil unless xml_node?(node) # Document nodes have no parent return nil if document?(node) node.parent end |
.parse(xml_string, options = {}) ⇒ Object
— Parsing —
22 23 24 25 26 27 28 |
# File 'lib/canon/xml_parsing.rb', line 22 def parse(xml_string, = {}) if XmlBackend.nokogiri? nokogiri_parse(xml_string, ) else moxml_parse(xml_string, ) end end |
.parse_fragment(xml_string) ⇒ Object
30 31 32 33 34 35 36 37 |
# File 'lib/canon/xml_parsing.rb', line 30 def parse_fragment(xml_string) if XmlBackend.nokogiri? Nokogiri::XML.fragment(xml_string).children.to_a else doc = moxml_context.parse("<__frag__>#{xml_string}</__frag__>") doc.root.children.to_a end end |
.processing_instruction?(node) ⇒ Boolean
104 105 106 107 108 109 110 |
# File 'lib/canon/xml_parsing.rb', line 104 def processing_instruction?(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::ProcessingInstruction) || node.is_a?(Moxml::ProcessingInstruction) else node.is_a?(Moxml::ProcessingInstruction) end end |
.serialize(node) ⇒ Object
— Serialization —
41 42 43 44 45 46 47 |
# File 'lib/canon/xml_parsing.rb', line 41 def serialize(node) if XmlBackend.nokogiri? nokogiri_serialize(node) else moxml_serialize(node) end end |
.text_content(node) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/canon/xml_parsing.rb', line 146 def text_content(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Node) ? node.content : node.to_s else case node when Moxml::Text, Moxml::Cdata, Moxml::Comment node.content.to_s when Moxml::Node node.text.to_s else node.to_s end end end |
.text_node?(node) ⇒ Boolean
80 81 82 83 84 85 86 |
# File 'lib/canon/xml_parsing.rb', line 80 def text_node?(node) if XmlBackend.nokogiri? node.is_a?(Nokogiri::XML::Text) || node.is_a?(Moxml::Text) else node.is_a?(Moxml::Text) end end |
.xml_node?(obj) ⇒ Boolean
64 65 66 67 68 69 70 |
# File 'lib/canon/xml_parsing.rb', line 64 def xml_node?(obj) if XmlBackend.nokogiri? obj.is_a?(Nokogiri::XML::Node) || obj.is_a?(Moxml::Node) else obj.is_a?(Moxml::Node) end end |