moxml 0.1.26 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/windows.yml +62 -0
  3. data/Gemfile +3 -1
  4. data/README.adoc +69 -6
  5. data/lib/compat/opal/moxml_boot.rb +5 -0
  6. data/lib/moxml/adapter/base.rb +53 -49
  7. data/lib/moxml/adapter/customized_leptris/declaration.rb +32 -0
  8. data/lib/moxml/adapter/customized_leptris/doctype.rb +31 -0
  9. data/lib/moxml/adapter/customized_leptris/entity_reference.rb +12 -0
  10. data/lib/moxml/adapter/customized_leptris/text_segment.rb +26 -0
  11. data/lib/moxml/adapter/customized_leptris.rb +16 -0
  12. data/lib/moxml/adapter/customized_libxml/cdata.rb +3 -12
  13. data/lib/moxml/adapter/customized_libxml/comment.rb +2 -9
  14. data/lib/moxml/adapter/customized_libxml/declaration.rb +1 -10
  15. data/lib/moxml/adapter/customized_libxml/node.rb +8 -0
  16. data/lib/moxml/adapter/customized_libxml/processing_instruction.rb +2 -10
  17. data/lib/moxml/adapter/customized_libxml/text.rb +2 -9
  18. data/lib/moxml/adapter/customized_oga/entity_decoder.rb +37 -0
  19. data/lib/moxml/adapter/customized_oga/raw_value_override.rb +52 -0
  20. data/lib/moxml/adapter/customized_oga/xml_generator.rb +4 -34
  21. data/lib/moxml/adapter/customized_oga.rb +2 -0
  22. data/lib/moxml/adapter/customized_ox/entity_reference.rb +1 -17
  23. data/lib/moxml/adapter/customized_rexml/entity_reference.rb +1 -11
  24. data/lib/moxml/adapter/headed_ox.rb +9 -128
  25. data/lib/moxml/adapter/leptris.rb +965 -0
  26. data/lib/moxml/adapter/libxml.rb +131 -99
  27. data/lib/moxml/adapter/nokogiri.rb +29 -8
  28. data/lib/moxml/adapter/oga.rb +91 -54
  29. data/lib/moxml/adapter/ox.rb +93 -137
  30. data/lib/moxml/adapter/rexml.rb +61 -50
  31. data/lib/moxml/adapter.rb +2 -1
  32. data/lib/moxml/attribute.rb +8 -4
  33. data/lib/moxml/attribute_resolver.rb +189 -0
  34. data/lib/moxml/config.rb +29 -3
  35. data/lib/moxml/context.rb +12 -0
  36. data/lib/moxml/element.rb +29 -12
  37. data/lib/moxml/entity/reference.rb +28 -0
  38. data/lib/moxml/entity.rb +125 -0
  39. data/lib/moxml/node.rb +90 -1
  40. data/lib/moxml/sax/namespace_splitter.rb +5 -2
  41. data/lib/moxml/signature/model/key/dsa_key_value.rb +1 -2
  42. data/lib/moxml/version.rb +1 -1
  43. data/lib/moxml/xml_emitter.rb +71 -0
  44. data/lib/moxml/xpath/compiler.rb +60 -7
  45. data/lib/moxml/xpath/parser.rb +22 -15
  46. data/lib/moxml.rb +3 -0
  47. data/spec/examples/readme_examples_spec.rb +0 -4
  48. data/spec/examples/xpath_examples_spec.rb +0 -11
  49. data/spec/integration/all_adapters_spec.rb +17 -0
  50. data/spec/integration/sax_parity_spec.rb +58 -0
  51. data/spec/integration/shared_examples/edge_cases.rb +0 -10
  52. data/spec/integration/shared_examples/integration_workflows.rb +0 -10
  53. data/spec/integration/shared_examples/node_wrappers/attribute_behavior.rb +98 -0
  54. data/spec/integration/shared_examples/node_wrappers/namespace_behavior.rb +26 -0
  55. data/spec/integration/shared_examples/node_wrappers/node_behavior.rb +0 -8
  56. data/spec/moxml/adapter/leptris_spec.rb +75 -0
  57. data/spec/moxml/adapter/ox_spec.rb +20 -6
  58. data/spec/moxml/adapter/platform_spec.rb +15 -2
  59. data/spec/moxml/adapter/shared_examples/adapter_contract.rb +180 -0
  60. data/spec/moxml/attribute_resolver_spec.rb +108 -0
  61. data/spec/moxml/doctype_spec.rb +1 -1
  62. data/spec/moxml/entity_spec.rb +76 -0
  63. data/spec/moxml/node_spec.rb +104 -0
  64. data/spec/moxml/sax_entity_parity_spec.rb +358 -0
  65. data/spec/moxml/xml_emitter_spec.rb +64 -0
  66. data/spec/moxml/xpath/axes_spec.rb +72 -0
  67. data/spec/moxml/xpath/parser_spec.rb +6 -0
  68. data/spec/moxml/xpath_capabilities_spec.rb +5 -3
  69. data/spec/performance/benchmark_spec.rb +13 -6
  70. data/spec/performance/thread_safety_spec.rb +0 -4
  71. data/spec/spec_helper.rb +5 -1
  72. metadata +21 -2
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Adapter
5
+ module CustomizedLeptris
6
+ # A text run split out of a native text node that carried entity
7
+ # markers. Value object: the moxml contract exposes text nodes as
8
+ # separate children around entity references, while libleptris
9
+ # stores them as one marker-bearing text node.
10
+ class TextSegment
11
+ attr_accessor :parent
12
+
13
+ attr_reader :content
14
+
15
+ def initialize(content, parent = nil)
16
+ @content = content
17
+ @parent = parent
18
+ end
19
+
20
+ def ==(other)
21
+ other.is_a?(self.class) && content == other.content
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Adapter
5
+ # Pure-Ruby node kinds that libleptris has no native representation
6
+ # for: XML declarations, programmatic DOCTYPEs, and entity references.
7
+ # The adapter stores them via NativeAttachment and serializes them
8
+ # from #to_xml.
9
+ module CustomizedLeptris
10
+ autoload :Declaration, "moxml/adapter/customized_leptris/declaration"
11
+ autoload :Doctype, "moxml/adapter/customized_leptris/doctype"
12
+ autoload :EntityReference, "moxml/adapter/customized_leptris/entity_reference"
13
+ autoload :TextSegment, "moxml/adapter/customized_leptris/text_segment"
14
+ end
15
+ end
16
+ end
@@ -5,19 +5,10 @@ module Moxml
5
5
  module CustomizedLibxml
6
6
  # Wrapper for LibXML CDATA section nodes
7
7
  class Cdata < Node
8
- # Serialize as XML CDATA section
9
- # LibXML auto-escapes content, we need to un-escape it
8
+ # libxml stores CDATA payload verbatim. Only the `]]>` end-marker
9
+ # needs splitting before re-wrapping.
10
10
  def to_xml
11
- content = @native.content
12
- .gsub("&quot;", '"')
13
- .gsub("&apos;", "'")
14
- .gsub("&lt;", "<")
15
- .gsub("&gt;", ">")
16
- .gsub("&amp;", "&")
17
-
18
- # Handle CDATA end marker escaping (]]> becomes ]]]]><![CDATA[>)
19
- # Replace all ]]> markers in the content before wrapping
20
- escaped_content = content.gsub("]]>", "]]]]><![CDATA[>")
11
+ escaped_content = @native.content.gsub("]]>", "]]]]><![CDATA[>")
21
12
  "<![CDATA[#{escaped_content}]]>"
22
13
  end
23
14
  end
@@ -5,16 +5,9 @@ module Moxml
5
5
  module CustomizedLibxml
6
6
  # Wrapper for LibXML comment nodes
7
7
  class Comment < Node
8
- # Serialize as XML comment
9
- # LibXML auto-escapes content, we need to un-escape it
8
+ # libxml stores comment payload verbatim.
10
9
  def to_xml
11
- content = @native.content
12
- .gsub("&quot;", '"')
13
- .gsub("&apos;", "'")
14
- .gsub("&lt;", "<")
15
- .gsub("&gt;", ">")
16
- .gsub("&amp;", "&")
17
- "<!--#{content}-->"
10
+ "<!--#{@native.content}-->"
18
11
  end
19
12
  end
20
13
  end
@@ -47,16 +47,7 @@ module Moxml
47
47
 
48
48
  # Generate XML declaration string
49
49
  def to_xml
50
- output = "<?xml version=\"#{@version}\""
51
- if @encoding && !@encoding.empty?
52
- output << " encoding=\"#{@encoding}\""
53
- end
54
- # Include standalone attribute if explicitly set (true or false)
55
- unless @standalone_value.nil?
56
- output << " standalone=\"#{standalone}\""
57
- end
58
- output << "?>"
59
- output
50
+ XmlEmitter.declaration_xml(@version, @encoding, standalone)
60
51
  end
61
52
 
62
53
  private
@@ -18,6 +18,14 @@ module Moxml
18
18
  @native = native_node
19
19
  end
20
20
 
21
+ # Swap the wrapped native node. Used by the Libxml adapter when
22
+ # libxml-ruby's content= setter would silently re-escape stored
23
+ # text; replacing the node with a fresh raw-storage instance is
24
+ # the only way to preserve verbatim content.
25
+ def replace_native!(fresh)
26
+ @native = fresh
27
+ end
28
+
21
29
  # Compare wrappers based on their native nodes
22
30
  def ==(other)
23
31
  return false unless other
@@ -5,20 +5,12 @@ module Moxml
5
5
  module CustomizedLibxml
6
6
  # Wrapper for LibXML processing instruction nodes
7
7
  class ProcessingInstruction < Node
8
- # Serialize as XML processing instruction
9
- # LibXML auto-escapes content, we need to un-escape it
8
+ # XML 1.0 §2.6: PI content is verbatim — no entity resolution, no escaping.
10
9
  def to_xml
11
10
  target = @native.name
12
11
  content = @native.content
13
-
14
- # Un-escape LibXML's automatic escaping
15
12
  if content && !content.empty?
16
- unescaped = content.gsub("&quot;", '"')
17
- .gsub("&apos;", "'")
18
- .gsub("&lt;", "<")
19
- .gsub("&gt;", ">")
20
- .gsub("&amp;", "&")
21
- "<?#{target} #{unescaped}?>"
13
+ "<?#{target} #{content}?>"
22
14
  else
23
15
  "<?#{target}?>"
24
16
  end
@@ -13,16 +13,9 @@ module Moxml
13
13
  @native.content
14
14
  end
15
15
 
16
- # Serialize as XML with proper escaping
17
- # LibXML's .content already contains escaped text, but it over-escapes
18
- # quotes which don't need escaping in text nodes (only in attributes)
16
+ # @native.to_s escapes & < > but leaves quotes alone, which text nodes need.
19
17
  def to_xml
20
- content = @native.content
21
- # Skip the gsub allocation entirely when there's nothing to undo —
22
- # the common case for parsed text without literal quotes.
23
- return content unless content.include?("&quot;")
24
-
25
- content.gsub("&quot;", '"')
18
+ @native.to_s
26
19
  end
27
20
  end
28
21
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "oga"
4
+
5
+ module Moxml
6
+ module Adapter
7
+ module CustomizedOga
8
+ # Override Oga::EntityDecoder.decode for XML inputs.
9
+ #
10
+ # Oga 3.4's stock Oga::XML::Entities.decode runs multiple passes,
11
+ # turning the well-formed "&amp;#38;" into "&" rather than the
12
+ # spec-correct "&#38;". XML 1.0 §4.6 forbids recursive resolution
13
+ # of parsed entities — exactly one decode pass is correct.
14
+ #
15
+ # Moxml::Adapter::Base.decode_entities does the single pass. HTML
16
+ # inputs fall through to Oga's stock HTML::Entities.decode, which
17
+ # has HTML-specific legacy rules that differ from XML's.
18
+ #
19
+ # Prepending on the singleton class means every Oga reader
20
+ # (Text#text, Attribute#value, etc.) automatically picks up the
21
+ # fixed decoder, so the adapter no longer needs to walk the parsed
22
+ # tree rewriting @text/@value ivars behind Oga's back.
23
+ module EntityDecoderOverride
24
+ # rubocop:disable-next Style/OptionalBooleanParameter -- must match Oga's signature
25
+ def decode(input, html = false)
26
+ return super if html
27
+
28
+ ::Moxml::Adapter::Base.decode_entities(input)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ Oga::EntityDecoder.singleton_class.prepend(
36
+ Moxml::Adapter::CustomizedOga::EntityDecoderOverride,
37
+ )
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "oga"
4
+
5
+ module Moxml
6
+ module Adapter
7
+ module CustomizedOga
8
+ # Bypass Oga's lazy decoder for user-authored values.
9
+ #
10
+ # Oga::XML::Attribute#value and Oga::XML::Text#text decode `@value` /
11
+ # `@text` on first read via Oga::EntityDecoder. EntityDecoderOverride
12
+ # makes that decode single-pass for parsed input. But user-authored
13
+ # values are already data — running them through the decoder again
14
+ # would re-interpret any literal `&` / `&#NN;` substrings as entity
15
+ # references. So we route the read through the NativeAttachment
16
+ # sidecar first; if the adapter stored the verbatim value there, we
17
+ # return it as-is, otherwise we fall through to Oga's normal read.
18
+ module RawValueOverride
19
+ def value
20
+ cached = ::Moxml::Adapter::Oga.attachments.get(self, :raw_value)
21
+ return cached unless cached.nil?
22
+
23
+ super
24
+ end
25
+
26
+ def value=(new_value)
27
+ ::Moxml::Adapter::Oga.attachments.set(self, :raw_value, new_value)
28
+ super
29
+ end
30
+
31
+ def text
32
+ cached = ::Moxml::Adapter::Oga.attachments.get(self, :raw_text)
33
+ return cached unless cached.nil?
34
+
35
+ super
36
+ end
37
+
38
+ def text=(new_value)
39
+ ::Moxml::Adapter::Oga.attachments.set(self, :raw_text, new_value)
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ Oga::XML::Attribute.prepend(
48
+ Moxml::Adapter::CustomizedOga::RawValueOverride,
49
+ )
50
+ Oga::XML::Text.prepend(
51
+ Moxml::Adapter::CustomizedOga::RawValueOverride,
52
+ )
@@ -45,36 +45,10 @@ module Moxml
45
45
  end
46
46
 
47
47
  def on_cdata(node, output)
48
- # Escape the end sequence
48
+ # Split any embedded end sequence into adjacent sections
49
49
  return super unless node.text.include?("]]>")
50
50
 
51
- chunks = node.text.split(/(\]\]>)/)
52
- chunks = ["]]", ">"] if chunks.size == 1
53
-
54
- while (index = chunks.index("]]>"))
55
- # the end tag cannot be the first and the last at the same time
56
-
57
- if index.zero?
58
- # it's the first text chunk
59
- chunks[index] = "]]"
60
- chunks[index + 1] = ">#{chunks[index + 1]}"
61
- elsif index - 1 == chunks.size
62
- # it's the last text chunk
63
- chunks[index - 1] += "]]"
64
- chunks[index] = ">"
65
- else
66
- # it's a chunk in the middle
67
- chunks[index - 1] += "]]"
68
- chunks[index + 1] = ">#{chunks[index + 1]}"
69
- chunks.delete_at(index)
70
- end
71
- end
72
-
73
- chunks.each do |chunk|
74
- output << "<![CDATA[#{chunk}]]>"
75
- end
76
-
77
- output
51
+ output << ::Moxml::XmlEmitter.cdata(node.text)
78
52
  end
79
53
 
80
54
  def on_processing_instruction(node, output)
@@ -91,12 +65,8 @@ module Moxml
91
65
  protected
92
66
 
93
67
  def encode(input)
94
- # similar to ::Oga::XML::Entities.encode_attribute
95
- input&.gsub(
96
- ::Oga::XML::Entities::ENCODE_ATTRIBUTE_REGEXP,
97
- # Keep apostrophes in attributes
98
- ::Oga::XML::Entities::ENCODE_ATTRIBUTE_MAPPING.merge("'" => "'"),
99
- )
68
+ # moxml-canonical attribute form: apostrophes stay literal
69
+ ::Moxml::XmlEmitter.escape_attribute(input.to_s)
100
70
  end
101
71
  end
102
72
  end
@@ -3,6 +3,8 @@
3
3
  module Moxml
4
4
  module Adapter
5
5
  module CustomizedOga
6
+ autoload :EntityDecoderOverride, "moxml/adapter/customized_oga/entity_decoder"
7
+ autoload :RawValueOverride, "moxml/adapter/customized_oga/raw_value_override"
6
8
  autoload :XmlDeclaration, "moxml/adapter/customized_oga/xml_declaration"
7
9
  autoload :XmlGenerator, "moxml/adapter/customized_oga/xml_generator"
8
10
  end
@@ -3,23 +3,7 @@
3
3
  module Moxml
4
4
  module Adapter
5
5
  module CustomizedOx
6
- class EntityReference
7
- attr_reader :name
8
- attr_accessor :parent
9
-
10
- def initialize(name)
11
- @name = name
12
- @parent = nil
13
- end
14
-
15
- def to_xml
16
- "&#{@name};"
17
- end
18
-
19
- def ==(other)
20
- other.is_a?(self.class) && @name == other.name
21
- end
22
- end
6
+ EntityReference = ::Moxml::Entity::Reference
23
7
  end
24
8
  end
25
9
  end
@@ -3,17 +3,7 @@
3
3
  module Moxml
4
4
  module Adapter
5
5
  module CustomizedRexml
6
- class EntityReference
7
- attr_reader :name
8
-
9
- def initialize(name)
10
- @name = name
11
- end
12
-
13
- def ==(other)
14
- other.is_a?(self.class) && @name == other.name
15
- end
16
- end
6
+ EntityReference = ::Moxml::Entity::Reference
17
7
  end
18
8
  end
19
9
  end
@@ -6,15 +6,13 @@ require "moxml/adapter/ox"
6
6
 
7
7
  module Moxml
8
8
  module Adapter
9
- # HeadedOx adapter - combines Ox's fast parsing with Moxml's XPath engine.
9
+ # HeadedOx adapter - Ox parsing with Moxml's XPath engine.
10
10
  #
11
- # This adapter uses:
12
- # - Ox for XML parsing (fast C-based parser)
13
- # - Moxml::XPath engine for comprehensive XPath 1.0 support
14
- #
15
- # Unlike the standard Ox adapter which has limited XPath support through
16
- # Ox's locate() method, HeadedOx provides full XPath 1.0 functionality
17
- # including all axes, predicates, and 27 standard functions.
11
+ # Since the Ox adapter now routes XPath through Moxml's pure-Ruby
12
+ # XPath 1.0 engine, HeadedOx is the historical name for exactly
13
+ # that combination and inherits everything from Adapter::Ox. It
14
+ # exists for backwards compatibility and reports its own
15
+ # capabilities.
18
16
  #
19
17
  # @example
20
18
  # context = Moxml.new(:headed_ox)
@@ -23,138 +21,23 @@ module Moxml
23
21
  #
24
22
  class HeadedOx < Ox
25
23
  class << self
26
- # Override parse to use lazy wrapping like the Ox adapter.
27
- # Previously used DocumentBuilder (eager tree construction causing
28
- # ~176K allocations per 100-element parse). Lazy parse defers wrapper
29
- # creation until nodes are accessed, matching Ox adapter behavior.
30
- def parse(xml, options = {}, _context = nil)
31
- processed_xml = preprocess_entities(xml)
32
- native_doc = begin
33
- result = ::Ox.parse(processed_xml)
34
-
35
- # result can be either Document or Element
36
- if result.is_a?(::Ox::Document)
37
- assign_parents(result)
38
- validate_single_root(result) if options[:strict]
39
- result
40
- else
41
- doc = ::Ox::Document.new
42
- doc << result
43
- assign_parents(doc)
44
- doc
45
- end
46
- rescue ::Ox::ParseError => e
47
- raise Moxml::ParseError.new(
48
- e.message,
49
- source: xml.is_a?(String) ? xml[0..100] : nil,
50
- )
51
- end
52
-
53
- # Use provided context if available, otherwise create new one
54
- ctx = _context || Context.new(:headed_ox)
55
- Document.new(native_doc, ctx)
56
- end
57
-
58
- # Execute XPath query using Moxml's XPath engine
59
- #
60
- # This overrides the Ox adapter's xpath method which uses locate().
61
- #
62
- # @param node Starting node (native or wrapped)
63
- # @param [String] expression XPath expression
64
- # @param [Hash] namespaces Namespace prefix mappings
65
- # @return [Array, Object] Native node array or scalar value
66
- def xpath(node, expression, namespaces = {})
67
- unless node.is_a?(Moxml::Node)
68
- ctx = Context.new(:headed_ox)
69
- node = Moxml::Node.wrap(node, ctx)
70
- end
71
-
72
- # Parse XPath expression to AST
73
- ast = XPath::Parser.parse(expression)
74
-
75
- # Compile AST to executable Proc using class method
76
- proc = XPath::Compiler.compile_with_cache(ast, namespaces: namespaces)
77
-
78
- # Execute on the node (now guaranteed to be wrapped Moxml node)
79
- result = proc.call(node)
80
-
81
- # Return native arrays for Node#xpath to wrap, scalars directly.
82
- # The adapter contract: xpath() returns Array<native> | scalar.
83
- case result
84
- when Array
85
- # XPath engine returns wrapped Moxml::Node objects.
86
- # Extract native nodes and deduplicate by object identity.
87
- native_nodes = result.map { |n| n.is_a?(Moxml::Node) ? n.native : n }
88
- seen = {}
89
- native_nodes.select do |native|
90
- id = native.object_id
91
- if seen[id]
92
- false
93
- else
94
- seen[id] = true
95
- end
96
- end
97
- when NodeSet
98
- # NodeSet from intermediate evaluation - extract natives and deduplicate
99
- seen = {}
100
- result.to_a.map(&:native).select do |native|
101
- id = native.object_id
102
- if seen[id]
103
- false
104
- else
105
- seen[id] = true
106
- end
107
- end
108
- else
109
- # Scalar values (string, number, boolean) - return as-is
110
- result
111
- end
112
- rescue StandardError => e
113
- raise Moxml::XPathError.new(
114
- "XPath execution failed: #{e.message}",
115
- expression: expression,
116
- adapter: "HeadedOx",
117
- node: node,
118
- )
119
- end
120
-
121
- # Execute XPath query and return first result
122
- #
123
- # @param [Moxml::Node] node Starting node
124
- # @param [String] expression XPath expression
125
- # @param [Hash] namespaces Namespace prefix mappings
126
- # @return [Object, nil] First native node or scalar value
127
- def at_xpath(node, expression, namespaces = {})
128
- result = xpath(node, expression, namespaces)
129
- result.is_a?(Array) ? result.first : result
130
- end
131
-
132
- # Check if XPath is supported
133
- #
134
- # @return [Boolean] Always true for HeadedOx
135
- def xpath_supported?
136
- true
24
+ def context_adapter_name
25
+ :headed_ox
137
26
  end
138
27
 
139
28
  # Report adapter capabilities
140
29
  #
141
- # HeadedOx extends Ox's capabilities with full XPath support
142
- # through Moxml's XPath engine
143
- #
144
30
  # @return [Hash] Capability flags
145
31
  def capabilities
146
32
  {
147
- # Core adapter capabilities
148
33
  parse: true,
149
-
150
- # Parsing capabilities (inherited from Ox)
151
34
  sax_parsing: true,
152
35
  namespace_aware: true,
153
36
  namespace_support: :partial,
154
37
  dtd_support: true,
155
38
  parsing_speed: :fast,
156
39
 
157
- # XPath capabilities (provided by Moxml's XPath engine)
40
+ # XPath via Moxml's XPath engine
158
41
  xpath_support: :full,
159
42
  xpath_full: true,
160
43
  xpath_axes: :partial, # 6 of 13 axes: child, descendant, descendant-or-self, self, attribute, parent
@@ -163,11 +46,9 @@ module Moxml
163
46
  xpath_namespaces: true,
164
47
  xpath_variables: true,
165
48
 
166
- # Serialization capabilities (inherited from Ox)
167
49
  namespace_serialization: true,
168
50
  pretty_print: true,
169
51
 
170
- # Known limitations
171
52
  schema_validation: false,
172
53
  xslt_support: false,
173
54
  }