moxml 0.1.7 → 0.1.8
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.
- checksums.yaml +4 -4
- data/.github/workflows/dependent-repos.json +5 -0
- data/.github/workflows/dependent-tests.yml +20 -0
- data/.github/workflows/docs.yml +59 -0
- data/.github/workflows/rake.yml +10 -10
- data/.github/workflows/release.yml +5 -3
- data/.gitignore +37 -0
- data/.rubocop.yml +15 -7
- data/.rubocop_todo.yml +238 -40
- data/Gemfile +14 -9
- data/LICENSE.md +6 -2
- data/README.adoc +535 -373
- data/Rakefile +53 -0
- data/benchmarks/.gitignore +6 -0
- data/benchmarks/generate_report.rb +550 -0
- data/docs/Gemfile +13 -0
- data/docs/_config.yml +138 -0
- data/docs/_guides/advanced-features.adoc +87 -0
- data/docs/_guides/development-testing.adoc +165 -0
- data/docs/_guides/index.adoc +45 -0
- data/docs/_guides/modifying-xml.adoc +293 -0
- data/docs/_guides/parsing-xml.adoc +231 -0
- data/docs/_guides/sax-parsing.adoc +603 -0
- data/docs/_guides/working-with-documents.adoc +118 -0
- data/docs/_pages/adapter-compatibility.adoc +369 -0
- data/docs/_pages/adapters/headed-ox.adoc +237 -0
- data/docs/_pages/adapters/index.adoc +98 -0
- data/docs/_pages/adapters/libxml.adoc +286 -0
- data/docs/_pages/adapters/nokogiri.adoc +252 -0
- data/docs/_pages/adapters/oga.adoc +292 -0
- data/docs/_pages/adapters/ox.adoc +55 -0
- data/docs/_pages/adapters/rexml.adoc +293 -0
- data/docs/_pages/best-practices.adoc +430 -0
- data/docs/_pages/compatibility.adoc +468 -0
- data/docs/_pages/configuration.adoc +251 -0
- data/docs/_pages/error-handling.adoc +350 -0
- data/docs/_pages/headed-ox-limitations.adoc +558 -0
- data/docs/_pages/headed-ox.adoc +1025 -0
- data/docs/_pages/index.adoc +35 -0
- data/docs/_pages/installation.adoc +141 -0
- data/docs/_pages/node-api-reference.adoc +50 -0
- data/docs/_pages/performance.adoc +36 -0
- data/docs/_pages/quick-start.adoc +244 -0
- data/docs/_pages/thread-safety.adoc +29 -0
- data/docs/_references/document-api.adoc +408 -0
- data/docs/_references/index.adoc +48 -0
- data/docs/_tutorials/basic-usage.adoc +268 -0
- data/docs/_tutorials/builder-pattern.adoc +343 -0
- data/docs/_tutorials/index.adoc +33 -0
- data/docs/_tutorials/namespace-handling.adoc +325 -0
- data/docs/_tutorials/xpath-queries.adoc +359 -0
- data/docs/index.adoc +122 -0
- data/examples/README.md +124 -0
- data/examples/api_client/README.md +424 -0
- data/examples/api_client/api_client.rb +394 -0
- data/examples/api_client/example_response.xml +48 -0
- data/examples/headed_ox_example/README.md +90 -0
- data/examples/headed_ox_example/headed_ox_demo.rb +71 -0
- data/examples/rss_parser/README.md +194 -0
- data/examples/rss_parser/example_feed.xml +93 -0
- data/examples/rss_parser/rss_parser.rb +189 -0
- data/examples/sax_parsing/README.md +50 -0
- data/examples/sax_parsing/data_extractor.rb +75 -0
- data/examples/sax_parsing/example.xml +21 -0
- data/examples/sax_parsing/large_file.rb +78 -0
- data/examples/sax_parsing/simple_parser.rb +55 -0
- data/examples/web_scraper/README.md +352 -0
- data/examples/web_scraper/example_page.html +201 -0
- data/examples/web_scraper/web_scraper.rb +312 -0
- data/lib/moxml/adapter/base.rb +107 -28
- data/lib/moxml/adapter/customized_libxml/cdata.rb +28 -0
- data/lib/moxml/adapter/customized_libxml/comment.rb +24 -0
- data/lib/moxml/adapter/customized_libxml/declaration.rb +85 -0
- data/lib/moxml/adapter/customized_libxml/element.rb +39 -0
- data/lib/moxml/adapter/customized_libxml/node.rb +44 -0
- data/lib/moxml/adapter/customized_libxml/processing_instruction.rb +31 -0
- data/lib/moxml/adapter/customized_libxml/text.rb +27 -0
- data/lib/moxml/adapter/customized_oga/xml_generator.rb +1 -1
- data/lib/moxml/adapter/customized_ox/attribute.rb +28 -1
- data/lib/moxml/adapter/customized_rexml/formatter.rb +11 -6
- data/lib/moxml/adapter/headed_ox.rb +161 -0
- data/lib/moxml/adapter/libxml.rb +1548 -0
- data/lib/moxml/adapter/nokogiri.rb +121 -9
- data/lib/moxml/adapter/oga.rb +123 -12
- data/lib/moxml/adapter/ox.rb +282 -26
- data/lib/moxml/adapter/rexml.rb +127 -20
- data/lib/moxml/adapter.rb +21 -4
- data/lib/moxml/attribute.rb +6 -0
- data/lib/moxml/builder.rb +40 -4
- data/lib/moxml/config.rb +8 -3
- data/lib/moxml/context.rb +39 -1
- data/lib/moxml/doctype.rb +13 -1
- data/lib/moxml/document.rb +39 -6
- data/lib/moxml/document_builder.rb +27 -5
- data/lib/moxml/element.rb +71 -2
- data/lib/moxml/error.rb +175 -6
- data/lib/moxml/node.rb +94 -3
- data/lib/moxml/node_set.rb +34 -0
- data/lib/moxml/sax/block_handler.rb +194 -0
- data/lib/moxml/sax/element_handler.rb +124 -0
- data/lib/moxml/sax/handler.rb +113 -0
- data/lib/moxml/sax.rb +31 -0
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xml_utils/encoder.rb +4 -4
- data/lib/moxml/xml_utils.rb +7 -4
- data/lib/moxml/xpath/ast/node.rb +159 -0
- data/lib/moxml/xpath/cache.rb +91 -0
- data/lib/moxml/xpath/compiler.rb +1768 -0
- data/lib/moxml/xpath/context.rb +26 -0
- data/lib/moxml/xpath/conversion.rb +124 -0
- data/lib/moxml/xpath/engine.rb +52 -0
- data/lib/moxml/xpath/errors.rb +101 -0
- data/lib/moxml/xpath/lexer.rb +304 -0
- data/lib/moxml/xpath/parser.rb +485 -0
- data/lib/moxml/xpath/ruby/generator.rb +269 -0
- data/lib/moxml/xpath/ruby/node.rb +193 -0
- data/lib/moxml/xpath.rb +37 -0
- data/lib/moxml.rb +5 -2
- data/moxml.gemspec +3 -1
- data/old-specs/moxml/adapter/customized_libxml/.gitkeep +6 -0
- data/spec/consistency/README.md +77 -0
- data/spec/{moxml/examples/adapter_spec.rb → consistency/adapter_parity_spec.rb} +4 -4
- data/spec/examples/README.md +75 -0
- data/spec/{support/shared_examples/examples/attribute.rb → examples/attribute_examples_spec.rb} +1 -1
- data/spec/{support/shared_examples/examples/basic_usage.rb → examples/basic_usage_spec.rb} +2 -2
- data/spec/{support/shared_examples/examples/namespace.rb → examples/namespace_examples_spec.rb} +3 -3
- data/spec/{support/shared_examples/examples/readme_examples.rb → examples/readme_examples_spec.rb} +6 -4
- data/spec/{support/shared_examples/examples/xpath.rb → examples/xpath_examples_spec.rb} +10 -6
- data/spec/integration/README.md +71 -0
- data/spec/{moxml/all_with_adapters_spec.rb → integration/all_adapters_spec.rb} +3 -2
- data/spec/integration/headed_ox_integration_spec.rb +326 -0
- data/spec/{support → integration}/shared_examples/edge_cases.rb +37 -10
- data/spec/integration/shared_examples/high_level/.gitkeep +0 -0
- data/spec/{support/shared_examples/context.rb → integration/shared_examples/high_level/context_behavior.rb} +2 -1
- data/spec/{support/shared_examples/integration.rb → integration/shared_examples/integration_workflows.rb} +23 -6
- data/spec/integration/shared_examples/node_wrappers/.gitkeep +0 -0
- data/spec/{support/shared_examples/cdata.rb → integration/shared_examples/node_wrappers/cdata_behavior.rb} +6 -1
- data/spec/{support/shared_examples/comment.rb → integration/shared_examples/node_wrappers/comment_behavior.rb} +2 -1
- data/spec/{support/shared_examples/declaration.rb → integration/shared_examples/node_wrappers/declaration_behavior.rb} +5 -2
- data/spec/{support/shared_examples/doctype.rb → integration/shared_examples/node_wrappers/doctype_behavior.rb} +2 -2
- data/spec/{support/shared_examples/document.rb → integration/shared_examples/node_wrappers/document_behavior.rb} +1 -1
- data/spec/{support/shared_examples/node.rb → integration/shared_examples/node_wrappers/node_behavior.rb} +9 -2
- data/spec/{support/shared_examples/node_set.rb → integration/shared_examples/node_wrappers/node_set_behavior.rb} +1 -18
- data/spec/{support/shared_examples/processing_instruction.rb → integration/shared_examples/node_wrappers/processing_instruction_behavior.rb} +6 -2
- data/spec/moxml/README.md +41 -0
- data/spec/moxml/adapter/.gitkeep +0 -0
- data/spec/moxml/adapter/README.md +61 -0
- data/spec/moxml/adapter/base_spec.rb +27 -0
- data/spec/moxml/adapter/headed_ox_spec.rb +311 -0
- data/spec/moxml/adapter/libxml_spec.rb +14 -0
- data/spec/moxml/adapter/ox_spec.rb +9 -8
- data/spec/moxml/adapter/shared_examples/.gitkeep +0 -0
- data/spec/{support/shared_examples/xml_adapter.rb → moxml/adapter/shared_examples/adapter_contract.rb} +39 -12
- data/spec/moxml/adapter_spec.rb +16 -0
- data/spec/moxml/attribute_spec.rb +30 -0
- data/spec/moxml/builder_spec.rb +33 -0
- data/spec/moxml/cdata_spec.rb +31 -0
- data/spec/moxml/comment_spec.rb +31 -0
- data/spec/moxml/config_spec.rb +3 -3
- data/spec/moxml/context_spec.rb +28 -0
- data/spec/moxml/declaration_spec.rb +36 -0
- data/spec/moxml/doctype_spec.rb +33 -0
- data/spec/moxml/document_builder_spec.rb +30 -0
- data/spec/moxml/document_spec.rb +105 -0
- data/spec/moxml/element_spec.rb +143 -0
- data/spec/moxml/error_spec.rb +266 -22
- data/spec/{moxml_spec.rb → moxml/moxml_spec.rb} +9 -9
- data/spec/moxml/namespace_spec.rb +32 -0
- data/spec/moxml/node_set_spec.rb +39 -0
- data/spec/moxml/node_spec.rb +37 -0
- data/spec/moxml/processing_instruction_spec.rb +34 -0
- data/spec/moxml/sax_spec.rb +1067 -0
- data/spec/moxml/text_spec.rb +31 -0
- data/spec/moxml/version_spec.rb +14 -0
- data/spec/moxml/xml_utils/.gitkeep +0 -0
- data/spec/moxml/xml_utils/encoder_spec.rb +27 -0
- data/spec/moxml/xml_utils_spec.rb +49 -0
- data/spec/moxml/xpath/ast/node_spec.rb +83 -0
- data/spec/moxml/xpath/axes_spec.rb +296 -0
- data/spec/moxml/xpath/cache_spec.rb +358 -0
- data/spec/moxml/xpath/compiler_spec.rb +406 -0
- data/spec/moxml/xpath/context_spec.rb +210 -0
- data/spec/moxml/xpath/conversion_spec.rb +365 -0
- data/spec/moxml/xpath/fixtures/sample.xml +25 -0
- data/spec/moxml/xpath/functions/boolean_functions_spec.rb +114 -0
- data/spec/moxml/xpath/functions/node_functions_spec.rb +145 -0
- data/spec/moxml/xpath/functions/numeric_functions_spec.rb +164 -0
- data/spec/moxml/xpath/functions/position_functions_spec.rb +93 -0
- data/spec/moxml/xpath/functions/special_functions_spec.rb +89 -0
- data/spec/moxml/xpath/functions/string_functions_spec.rb +381 -0
- data/spec/moxml/xpath/lexer_spec.rb +488 -0
- data/spec/moxml/xpath/parser_integration_spec.rb +210 -0
- data/spec/moxml/xpath/parser_spec.rb +364 -0
- data/spec/moxml/xpath/ruby/generator_spec.rb +421 -0
- data/spec/moxml/xpath/ruby/node_spec.rb +291 -0
- data/spec/moxml/xpath_capabilities_spec.rb +199 -0
- data/spec/moxml/xpath_spec.rb +77 -0
- data/spec/performance/README.md +83 -0
- data/spec/performance/benchmark_spec.rb +64 -0
- data/spec/{support/shared_examples/examples/memory.rb → performance/memory_usage_spec.rb} +3 -1
- data/spec/{support/shared_examples/examples/thread_safety.rb → performance/thread_safety_spec.rb} +3 -1
- data/spec/performance/xpath_benchmark_spec.rb +259 -0
- data/spec/spec_helper.rb +58 -1
- data/spec/support/xml_matchers.rb +1 -1
- metadata +176 -34
- data/spec/support/shared_examples/examples/benchmark_spec.rb +0 -51
- /data/spec/{support/shared_examples/builder.rb → integration/shared_examples/high_level/builder_behavior.rb} +0 -0
- /data/spec/{support/shared_examples/document_builder.rb → integration/shared_examples/high_level/document_builder_behavior.rb} +0 -0
- /data/spec/{support/shared_examples/attribute.rb → integration/shared_examples/node_wrappers/attribute_behavior.rb} +0 -0
- /data/spec/{support/shared_examples/element.rb → integration/shared_examples/node_wrappers/element_behavior.rb} +0 -0
- /data/spec/{support/shared_examples/namespace.rb → integration/shared_examples/node_wrappers/namespace_behavior.rb} +0 -0
- /data/spec/{support/shared_examples/text.rb → integration/shared_examples/node_wrappers/text_behavior.rb} +0 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Compatibility
|
|
3
|
+
parent: Overview
|
|
4
|
+
nav_order: 6
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
== Compatibility
|
|
8
|
+
|
|
9
|
+
=== Purpose
|
|
10
|
+
|
|
11
|
+
This page provides a comprehensive comparison of features, performance, and
|
|
12
|
+
capabilities across all supported XML adapters.
|
|
13
|
+
|
|
14
|
+
=== Feature compatibility matrix
|
|
15
|
+
|
|
16
|
+
[cols="3,1,1,1,1,1", options="header"]
|
|
17
|
+
|===
|
|
18
|
+
| Feature/Operation | Nokogiri | Oga | REXML | LibXML | Ox
|
|
19
|
+
|
|
20
|
+
| **Core operations**
|
|
21
|
+
|
|
|
22
|
+
|
|
|
23
|
+
|
|
|
24
|
+
|
|
|
25
|
+
|
|
|
26
|
+
|
|
27
|
+
| Parse XML string
|
|
28
|
+
| ✅ Full
|
|
29
|
+
| ✅ Full
|
|
30
|
+
| ✅ Full
|
|
31
|
+
| ✅ Full
|
|
32
|
+
| ✅ Full
|
|
33
|
+
|
|
34
|
+
| Parse XML file/IO
|
|
35
|
+
| ✅ Full
|
|
36
|
+
| ✅ Full
|
|
37
|
+
| ✅ Full
|
|
38
|
+
| ✅ Full
|
|
39
|
+
| ✅ Full
|
|
40
|
+
|
|
41
|
+
| Serialize to XML
|
|
42
|
+
| ✅ Full
|
|
43
|
+
| ✅ Full
|
|
44
|
+
| ✅ Full
|
|
45
|
+
| ✅ Full
|
|
46
|
+
| ✅ Full
|
|
47
|
+
|
|
48
|
+
| **Element operations**
|
|
49
|
+
|
|
|
50
|
+
|
|
|
51
|
+
|
|
|
52
|
+
|
|
|
53
|
+
|
|
|
54
|
+
|
|
55
|
+
| Create elements
|
|
56
|
+
| ✅ Full
|
|
57
|
+
| ✅ Full
|
|
58
|
+
| ✅ Full
|
|
59
|
+
| ✅ Full
|
|
60
|
+
| ✅ Full
|
|
61
|
+
|
|
62
|
+
| Get/set attributes
|
|
63
|
+
| ✅ Full
|
|
64
|
+
| ✅ Full
|
|
65
|
+
| ✅ Full
|
|
66
|
+
| ✅ Full
|
|
67
|
+
| ✅ Full
|
|
68
|
+
|
|
69
|
+
| Add/remove children
|
|
70
|
+
| ✅ Full
|
|
71
|
+
| ✅ Full
|
|
72
|
+
| ✅ Full
|
|
73
|
+
| ✅ Full
|
|
74
|
+
| ✅ Full
|
|
75
|
+
|
|
76
|
+
| Replace nodes
|
|
77
|
+
| ✅ Full
|
|
78
|
+
| ✅ Full
|
|
79
|
+
| ✅ Full
|
|
80
|
+
| ✅ Full
|
|
81
|
+
| ⚠️ Limited^1^
|
|
82
|
+
|
|
83
|
+
| **Namespace operations**
|
|
84
|
+
|
|
|
85
|
+
|
|
|
86
|
+
|
|
|
87
|
+
|
|
|
88
|
+
|
|
|
89
|
+
|
|
90
|
+
| Add namespaces
|
|
91
|
+
| ✅ Full
|
|
92
|
+
| ✅ Full
|
|
93
|
+
| ✅ Full
|
|
94
|
+
| ✅ Full
|
|
95
|
+
| ✅ Full
|
|
96
|
+
|
|
97
|
+
| Default namespaces
|
|
98
|
+
| ✅ Full
|
|
99
|
+
| ✅ Full
|
|
100
|
+
| ✅ Full
|
|
101
|
+
| ✅ Full
|
|
102
|
+
| ⚠️ Basic
|
|
103
|
+
|
|
104
|
+
| Namespace inheritance
|
|
105
|
+
| ✅ Full
|
|
106
|
+
| ✅ Full
|
|
107
|
+
| ✅ Full
|
|
108
|
+
| ✅ Full
|
|
109
|
+
| ❌ None
|
|
110
|
+
|
|
111
|
+
| Namespaced attributes
|
|
112
|
+
| ✅ Full
|
|
113
|
+
| ✅ Full
|
|
114
|
+
| ✅ Full
|
|
115
|
+
| ✅ Full
|
|
116
|
+
| ⚠️ Limited
|
|
117
|
+
|
|
118
|
+
| **XPath queries**
|
|
119
|
+
|
|
|
120
|
+
|
|
|
121
|
+
|
|
|
122
|
+
|
|
|
123
|
+
|
|
|
124
|
+
|
|
125
|
+
| Basic paths (`//element`)
|
|
126
|
+
| ✅ Full
|
|
127
|
+
| ✅ Full
|
|
128
|
+
| ✅ Full
|
|
129
|
+
| ✅ Full
|
|
130
|
+
| ✅ Full
|
|
131
|
+
|
|
132
|
+
| Attribute predicates (`[@id]`)
|
|
133
|
+
| ✅ Full
|
|
134
|
+
| ✅ Full
|
|
135
|
+
| ✅ Full
|
|
136
|
+
| ✅ Full
|
|
137
|
+
| ⚠️ Name only^2^
|
|
138
|
+
|
|
139
|
+
| Attribute values (`[@id='123']`)
|
|
140
|
+
| ✅ Full
|
|
141
|
+
| ✅ Full
|
|
142
|
+
| ✅ Full
|
|
143
|
+
| ✅ Full
|
|
144
|
+
| ❌ None^3^
|
|
145
|
+
|
|
146
|
+
| Logical operators
|
|
147
|
+
| ✅ Full
|
|
148
|
+
| ✅ Full
|
|
149
|
+
| ✅ Full
|
|
150
|
+
| ✅ Full
|
|
151
|
+
| ❌ None
|
|
152
|
+
|
|
153
|
+
| Position predicates
|
|
154
|
+
| ✅ Full
|
|
155
|
+
| ✅ Full
|
|
156
|
+
| ✅ Full
|
|
157
|
+
| ✅ Full
|
|
158
|
+
| ❌ None
|
|
159
|
+
|
|
160
|
+
| Text predicates
|
|
161
|
+
| ✅ Full
|
|
162
|
+
| ✅ Full
|
|
163
|
+
| ✅ Full
|
|
164
|
+
| ✅ Full
|
|
165
|
+
| ❌ None
|
|
166
|
+
|
|
167
|
+
| Namespace XPath
|
|
168
|
+
| ✅ Full
|
|
169
|
+
| ✅ Full
|
|
170
|
+
| ❌ None
|
|
171
|
+
| ✅ Full
|
|
172
|
+
| ❌ None
|
|
173
|
+
|
|
174
|
+
| Parent axis (`..`)
|
|
175
|
+
| ✅ Full
|
|
176
|
+
| ✅ Full
|
|
177
|
+
| ✅ Full
|
|
178
|
+
| ✅ Full
|
|
179
|
+
| ❌ None
|
|
180
|
+
|
|
181
|
+
| Sibling axes
|
|
182
|
+
| ✅ Full
|
|
183
|
+
| ✅ Full
|
|
184
|
+
| ✅ Full
|
|
185
|
+
| ✅ Full
|
|
186
|
+
| ❌ None
|
|
187
|
+
|
|
188
|
+
| XPath functions
|
|
189
|
+
| ✅ Full
|
|
190
|
+
| ✅ Full
|
|
191
|
+
| ✅ Full
|
|
192
|
+
| ✅ Full
|
|
193
|
+
| ❌ None
|
|
194
|
+
|
|
195
|
+
| **Special content**
|
|
196
|
+
|
|
|
197
|
+
|
|
|
198
|
+
|
|
|
199
|
+
|
|
|
200
|
+
|
|
|
201
|
+
|
|
202
|
+
| CDATA sections
|
|
203
|
+
| ✅ Full
|
|
204
|
+
| ✅ Full
|
|
205
|
+
| ✅ Full
|
|
206
|
+
| ✅ Full
|
|
207
|
+
| ✅ Full
|
|
208
|
+
|
|
209
|
+
| Comments
|
|
210
|
+
| ✅ Full
|
|
211
|
+
| ✅ Full
|
|
212
|
+
| ✅ Full
|
|
213
|
+
| ✅ Full
|
|
214
|
+
| ✅ Full
|
|
215
|
+
|
|
216
|
+
| Processing instructions
|
|
217
|
+
| ✅ Full
|
|
218
|
+
| ✅ Full
|
|
219
|
+
| ✅ Full
|
|
220
|
+
| ✅ Full
|
|
221
|
+
| ✅ Full
|
|
222
|
+
|
|
223
|
+
| DOCTYPE declarations
|
|
224
|
+
| ✅ Full
|
|
225
|
+
| ✅ Full
|
|
226
|
+
| ✅ Full
|
|
227
|
+
| ⚠️ Limited^4^
|
|
228
|
+
| ✅ Full
|
|
229
|
+
|
|
230
|
+
| **Performance**
|
|
231
|
+
|
|
|
232
|
+
|
|
|
233
|
+
|
|
|
234
|
+
|
|
|
235
|
+
|
|
|
236
|
+
|
|
237
|
+
| Parse speed
|
|
238
|
+
| Fast
|
|
239
|
+
| Fast
|
|
240
|
+
| Medium
|
|
241
|
+
| Very Fast
|
|
242
|
+
| Very Fast
|
|
243
|
+
|
|
244
|
+
| Serialize speed
|
|
245
|
+
| Fast
|
|
246
|
+
| Fast
|
|
247
|
+
| Medium
|
|
248
|
+
| Very Fast
|
|
249
|
+
| Fastest
|
|
250
|
+
|
|
251
|
+
| Memory usage
|
|
252
|
+
| Good
|
|
253
|
+
| Medium
|
|
254
|
+
| Medium
|
|
255
|
+
| Excellent
|
|
256
|
+
| Best
|
|
257
|
+
|
|
258
|
+
| Thread safety
|
|
259
|
+
| ✅ Yes
|
|
260
|
+
| ✅ Yes
|
|
261
|
+
| ✅ Yes
|
|
262
|
+
| ✅ Yes
|
|
263
|
+
| ✅ Yes
|
|
264
|
+
|===
|
|
265
|
+
|
|
266
|
+
=== Legend
|
|
267
|
+
|
|
268
|
+
✅ Full:: Complete support with no limitations
|
|
269
|
+
⚠️ Limited:: Partial support with workarounds available
|
|
270
|
+
❌ None:: Not supported
|
|
271
|
+
|
|
272
|
+
=== Footnotes
|
|
273
|
+
|
|
274
|
+
^1^ Ox: Text node replacement may fail in some cases due to internal node
|
|
275
|
+
structure
|
|
276
|
+
|
|
277
|
+
^2^ Ox: `//book[@id]` returns all book elements (doesn't filter by attribute
|
|
278
|
+
existence)
|
|
279
|
+
|
|
280
|
+
^3^ Ox: Use `.find { |el| el["id"] == "123" }` instead of XPath attribute
|
|
281
|
+
value predicates
|
|
282
|
+
|
|
283
|
+
^4^ LibXML: DOCTYPE parsing works, serialization is limited (no perfect
|
|
284
|
+
round-trip)
|
|
285
|
+
|
|
286
|
+
=== Performance comparison
|
|
287
|
+
|
|
288
|
+
==== Parsing performance (medium 10KB XML)
|
|
289
|
+
|
|
290
|
+
[source]
|
|
291
|
+
----
|
|
292
|
+
Ox ████████████████████████████████████████████████ 289 ips
|
|
293
|
+
LibXML ███████████████████████████████████ 120 ips
|
|
294
|
+
Nokogiri █████████████████ 76 ips
|
|
295
|
+
Oga ███████████ 50 ips
|
|
296
|
+
REXML ████ 15 ips
|
|
297
|
+
----
|
|
298
|
+
|
|
299
|
+
==== Serialization performance
|
|
300
|
+
|
|
301
|
+
[source]
|
|
302
|
+
----
|
|
303
|
+
Ox ████████████████████████████████████████████████ 39,203 ips
|
|
304
|
+
Nokogiri █████████████████ 13,900 ips
|
|
305
|
+
LibXML ███████ 5,600 ips
|
|
306
|
+
Oga ████ 3,200 ips
|
|
307
|
+
REXML ██ 1,500 ips
|
|
308
|
+
----
|
|
309
|
+
|
|
310
|
+
==== XPath performance (simple queries)
|
|
311
|
+
|
|
312
|
+
[source]
|
|
313
|
+
----
|
|
314
|
+
Nokogiri ████████████████████████████████████████████████ 64,958 ips
|
|
315
|
+
LibXML ███████████████████████████████████████████████ 62,000 ips
|
|
316
|
+
Oga ███████████████████████ 28,000 ips
|
|
317
|
+
REXML ███████ 8,500 ips
|
|
318
|
+
Ox ███████ 9,640 ips
|
|
319
|
+
----
|
|
320
|
+
|
|
321
|
+
NOTE: Performance numbers are approximate and vary by system and document
|
|
322
|
+
complexity.
|
|
323
|
+
|
|
324
|
+
=== Memory usage comparison
|
|
325
|
+
|
|
326
|
+
[cols="2,2,3"]
|
|
327
|
+
|===
|
|
328
|
+
| Adapter | Memory delta | Description
|
|
329
|
+
|
|
330
|
+
| Ox
|
|
331
|
+
| 0.0 MB
|
|
332
|
+
| Best - minimal allocation
|
|
333
|
+
|
|
334
|
+
| Nokogiri
|
|
335
|
+
| -0.1 MB
|
|
336
|
+
| Excellent efficiency
|
|
337
|
+
|
|
338
|
+
| LibXML
|
|
339
|
+
| +0.1 MB
|
|
340
|
+
| Very good
|
|
341
|
+
|
|
342
|
+
| Oga
|
|
343
|
+
| +0.3 MB
|
|
344
|
+
| Good for pure Ruby
|
|
345
|
+
|
|
346
|
+
| REXML
|
|
347
|
+
| +0.5 MB
|
|
348
|
+
| Medium overhead
|
|
349
|
+
|===
|
|
350
|
+
|
|
351
|
+
=== XPath capability summary
|
|
352
|
+
|
|
353
|
+
[cols="2,4"]
|
|
354
|
+
|===
|
|
355
|
+
| Capability level | Adapters
|
|
356
|
+
|
|
357
|
+
| Full XPath 1.0
|
|
358
|
+
| Nokogiri, LibXML, Oga
|
|
359
|
+
|
|
360
|
+
| Basic XPath
|
|
361
|
+
| REXML (no namespaces), Ox (no predicates)
|
|
362
|
+
|
|
363
|
+
| Ruby workarounds needed
|
|
364
|
+
| Ox, REXML (for complex queries)
|
|
365
|
+
|===
|
|
366
|
+
|
|
367
|
+
=== Adapter selection decision tree
|
|
368
|
+
|
|
369
|
+
[source]
|
|
370
|
+
----
|
|
371
|
+
Need pure Ruby?
|
|
372
|
+
├─ Yes
|
|
373
|
+
│ ├─ Need full XPath? → Oga
|
|
374
|
+
│ ├─ No external gems? → REXML
|
|
375
|
+
│ └─ Basic XPath OK? → REXML
|
|
376
|
+
└─ No (C extensions OK)
|
|
377
|
+
├─ Need maximum speed? → Ox
|
|
378
|
+
├─ Simple documents? → Ox
|
|
379
|
+
├─ Complex XPath? → Nokogiri or LibXML
|
|
380
|
+
├─ Industry standard? → Nokogiri
|
|
381
|
+
└─ Alternative to Nokogiri? → LibXML
|
|
382
|
+
----
|
|
383
|
+
|
|
384
|
+
=== Recommendations by use case
|
|
385
|
+
|
|
386
|
+
[cols="2,2,3"]
|
|
387
|
+
|===
|
|
388
|
+
| Use case | Primary choice | Alternative
|
|
389
|
+
|
|
390
|
+
| General XML processing
|
|
391
|
+
| Nokogiri
|
|
392
|
+
| LibXML
|
|
393
|
+
|
|
394
|
+
| Maximum performance
|
|
395
|
+
| Ox
|
|
396
|
+
| LibXML
|
|
397
|
+
|
|
398
|
+
| Pure Ruby requirement
|
|
399
|
+
| Oga
|
|
400
|
+
| REXML
|
|
401
|
+
|
|
402
|
+
| No external dependencies
|
|
403
|
+
| REXML
|
|
404
|
+
| N/A
|
|
405
|
+
|
|
406
|
+
| Complex XPath queries
|
|
407
|
+
| Nokogiri
|
|
408
|
+
| LibXML, Oga
|
|
409
|
+
|
|
410
|
+
| High-throughput simple docs
|
|
411
|
+
| Ox
|
|
412
|
+
| LibXML
|
|
413
|
+
|
|
414
|
+
| Namespace-heavy documents
|
|
415
|
+
| Nokogiri
|
|
416
|
+
| LibXML, Oga
|
|
417
|
+
|
|
418
|
+
| Memory-constrained
|
|
419
|
+
| Ox
|
|
420
|
+
| Nokogiri
|
|
421
|
+
|===
|
|
422
|
+
|
|
423
|
+
=== Testing across adapters
|
|
424
|
+
|
|
425
|
+
To ensure your code works across adapters:
|
|
426
|
+
|
|
427
|
+
[source,ruby]
|
|
428
|
+
----
|
|
429
|
+
# Test with multiple adapters
|
|
430
|
+
[:nokogiri, :libxml, :oga, :rexml, :ox].each do |adapter_name|
|
|
431
|
+
next unless adapter_available?(adapter_name)
|
|
432
|
+
|
|
433
|
+
context = Moxml.new
|
|
434
|
+
context.config.adapter = adapter_name
|
|
435
|
+
|
|
436
|
+
doc = context.parse(xml)
|
|
437
|
+
|
|
438
|
+
# Test your operations
|
|
439
|
+
results = doc.xpath('//book')
|
|
440
|
+
# Add assertions
|
|
441
|
+
end
|
|
442
|
+
----
|
|
443
|
+
|
|
444
|
+
=== Migration guide
|
|
445
|
+
|
|
446
|
+
**From Nokogiri to Ox:**
|
|
447
|
+
|
|
448
|
+
* Replace complex XPath with Ruby filtering
|
|
449
|
+
* Test namespace operations carefully
|
|
450
|
+
* Verify text node replacements work
|
|
451
|
+
|
|
452
|
+
**From REXML to Nokogiri/LibXML:**
|
|
453
|
+
|
|
454
|
+
* No code changes needed
|
|
455
|
+
* XPath queries will work better automatically
|
|
456
|
+
* Performance will improve significantly
|
|
457
|
+
|
|
458
|
+
**From Ox to Nokogiri:**
|
|
459
|
+
|
|
460
|
+
* Complex XPath will work automatically
|
|
461
|
+
* No workarounds needed
|
|
462
|
+
* Performance may decrease for parsing
|
|
463
|
+
|
|
464
|
+
=== See also
|
|
465
|
+
|
|
466
|
+
* link:adapters/[Individual adapter documentation]
|
|
467
|
+
* link:../guides/adapter-switching[Adapter switching guide]
|
|
468
|
+
* link:../guides/performance-optimization[Performance optimization]
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
parent: Overview
|
|
4
|
+
nav_order: 7
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
== Configuration
|
|
8
|
+
|
|
9
|
+
=== Purpose
|
|
10
|
+
|
|
11
|
+
Learn how to configure Moxml for your application's requirements including
|
|
12
|
+
adapter selection, parsing options, and encoding settings.
|
|
13
|
+
|
|
14
|
+
=== Global configuration
|
|
15
|
+
|
|
16
|
+
Configure Moxml globally for your application:
|
|
17
|
+
|
|
18
|
+
[source,ruby]
|
|
19
|
+
----
|
|
20
|
+
# Set default adapter
|
|
21
|
+
Moxml::Config.default_adapter = :nokogiri
|
|
22
|
+
|
|
23
|
+
# Access global config
|
|
24
|
+
config = Moxml::Config.new
|
|
25
|
+
config.adapter = :libxml
|
|
26
|
+
config.strict_parsing = true
|
|
27
|
+
config.default_encoding = 'UTF-8'
|
|
28
|
+
----
|
|
29
|
+
|
|
30
|
+
=== Instance configuration
|
|
31
|
+
|
|
32
|
+
Configure per Moxml instance:
|
|
33
|
+
|
|
34
|
+
[source,ruby]
|
|
35
|
+
----
|
|
36
|
+
# During initialization
|
|
37
|
+
context = Moxml.new do |config|
|
|
38
|
+
config.adapter = :oga
|
|
39
|
+
config.strict_parsing = false
|
|
40
|
+
config.default_encoding = 'ISO-8859-1'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# After creation
|
|
44
|
+
context = Moxml.new
|
|
45
|
+
context.config.adapter = :libxml
|
|
46
|
+
context.config.strict_parsing = true
|
|
47
|
+
----
|
|
48
|
+
|
|
49
|
+
=== Configuration options
|
|
50
|
+
|
|
51
|
+
==== Adapter selection
|
|
52
|
+
|
|
53
|
+
Choose the XML processing library:
|
|
54
|
+
|
|
55
|
+
[source,ruby]
|
|
56
|
+
----
|
|
57
|
+
context = Moxml.new
|
|
58
|
+
context.config.adapter = :nokogiri # or :libxml, :oga, :rexml, :ox
|
|
59
|
+
----
|
|
60
|
+
|
|
61
|
+
**Available adapters:**
|
|
62
|
+
|
|
63
|
+
* `:nokogiri` - Default, full features
|
|
64
|
+
* `:libxml` - Native performance
|
|
65
|
+
* `:oga` - Pure Ruby
|
|
66
|
+
* `:rexml` - Standard library
|
|
67
|
+
* `:ox` - Maximum speed
|
|
68
|
+
|
|
69
|
+
See link:adapters/[Adapters documentation] for details.
|
|
70
|
+
|
|
71
|
+
==== Strict parsing
|
|
72
|
+
|
|
73
|
+
Control error handling for malformed XML:
|
|
74
|
+
|
|
75
|
+
[source,ruby]
|
|
76
|
+
----
|
|
77
|
+
# Strict mode (recommended for production)
|
|
78
|
+
context.config.strict_parsing = true
|
|
79
|
+
doc = context.parse(xml) # Raises ParseError on malformed XML
|
|
80
|
+
|
|
81
|
+
# Relaxed mode (attempt to parse malformed XML)
|
|
82
|
+
context.config.strict_parsing = false
|
|
83
|
+
doc = context.parse(xml) # Attempts to recover from errors
|
|
84
|
+
----
|
|
85
|
+
|
|
86
|
+
**Default:** `true`
|
|
87
|
+
|
|
88
|
+
==== Default encoding
|
|
89
|
+
|
|
90
|
+
Set default character encoding:
|
|
91
|
+
|
|
92
|
+
[source,ruby]
|
|
93
|
+
----
|
|
94
|
+
context.config.default_encoding = 'UTF-8' # Default
|
|
95
|
+
context.config.default_encoding = 'ISO-8859-1'
|
|
96
|
+
context.config.default_encoding = 'UTF-16'
|
|
97
|
+
----
|
|
98
|
+
|
|
99
|
+
**Default:** `"UTF-8"`
|
|
100
|
+
|
|
101
|
+
=== Context switching
|
|
102
|
+
|
|
103
|
+
Use different configurations for different tasks:
|
|
104
|
+
|
|
105
|
+
[source,ruby]
|
|
106
|
+
----
|
|
107
|
+
# High-performance context for simple docs
|
|
108
|
+
fast_context = Moxml.new
|
|
109
|
+
fast_context.config.adapter = :ox
|
|
110
|
+
|
|
111
|
+
# Feature-rich context for complex docs
|
|
112
|
+
full_context = Moxml.new
|
|
113
|
+
full_context.config.adapter = :nokogiri
|
|
114
|
+
|
|
115
|
+
# Process based on requirements
|
|
116
|
+
if simple_document?(xml)
|
|
117
|
+
doc = fast_context.parse(xml)
|
|
118
|
+
else
|
|
119
|
+
doc = full_context.parse(xml)
|
|
120
|
+
end
|
|
121
|
+
----
|
|
122
|
+
|
|
123
|
+
=== Serialization options
|
|
124
|
+
|
|
125
|
+
Control XML output format:
|
|
126
|
+
|
|
127
|
+
[source,ruby]
|
|
128
|
+
----
|
|
129
|
+
xml = doc.to_xml(
|
|
130
|
+
indent: 2, # Indentation spaces
|
|
131
|
+
encoding: 'UTF-8', # Output encoding
|
|
132
|
+
no_declaration: false, # Include <?xml ...?>
|
|
133
|
+
expand_empty: false # Expand empty tags <tag></tag>
|
|
134
|
+
)
|
|
135
|
+
----
|
|
136
|
+
|
|
137
|
+
=== Adapter-specific configuration
|
|
138
|
+
|
|
139
|
+
Some adapters support additional options:
|
|
140
|
+
|
|
141
|
+
==== Nokogiri
|
|
142
|
+
|
|
143
|
+
[source,ruby]
|
|
144
|
+
----
|
|
145
|
+
# Nokogiri parse options
|
|
146
|
+
doc = context.parse(xml,
|
|
147
|
+
strict: true,
|
|
148
|
+
encoding: 'UTF-8',
|
|
149
|
+
recover: false # Don't recover from errors
|
|
150
|
+
)
|
|
151
|
+
----
|
|
152
|
+
|
|
153
|
+
==== LibXML
|
|
154
|
+
|
|
155
|
+
[source,ruby]
|
|
156
|
+
----
|
|
157
|
+
# LibXML parse options
|
|
158
|
+
doc = context.parse(xml,
|
|
159
|
+
strict: true,
|
|
160
|
+
encoding: 'UTF-8'
|
|
161
|
+
)
|
|
162
|
+
----
|
|
163
|
+
|
|
164
|
+
==== Ox
|
|
165
|
+
|
|
166
|
+
[source,ruby]
|
|
167
|
+
----
|
|
168
|
+
# Ox typically uses fewer options
|
|
169
|
+
doc = context.parse(xml)
|
|
170
|
+
----
|
|
171
|
+
|
|
172
|
+
=== Configuration best practices
|
|
173
|
+
|
|
174
|
+
. **Set adapter explicitly** in production for consistency
|
|
175
|
+
. **Use strict parsing** to catch XML errors early
|
|
176
|
+
. **Specify encoding** when working with non-UTF-8 documents
|
|
177
|
+
. **Document configuration** in your application setup
|
|
178
|
+
. **Test with target adapter** during development
|
|
179
|
+
|
|
180
|
+
=== Environment-based configuration
|
|
181
|
+
|
|
182
|
+
Configure based on environment:
|
|
183
|
+
|
|
184
|
+
[source,ruby]
|
|
185
|
+
----
|
|
186
|
+
# config/initializers/moxml.rb
|
|
187
|
+
case Rails.env
|
|
188
|
+
when 'production'
|
|
189
|
+
Moxml::Config.default_adapter = :nokogiri
|
|
190
|
+
Moxml.new.config.strict_parsing = true
|
|
191
|
+
when 'development'
|
|
192
|
+
Moxml::Config.default_adapter = :nokogiri
|
|
193
|
+
Moxml.new.config.strict_parsing = false
|
|
194
|
+
when 'test'
|
|
195
|
+
Moxml::Config.default_adapter = :rexml # No C extensions needed
|
|
196
|
+
end
|
|
197
|
+
----
|
|
198
|
+
|
|
199
|
+
=== Runtime adapter switching
|
|
200
|
+
|
|
201
|
+
Change adapters dynamically:
|
|
202
|
+
|
|
203
|
+
[source,ruby]
|
|
204
|
+
----
|
|
205
|
+
def process_with_best_adapter(xml)
|
|
206
|
+
# Try fast adapter first
|
|
207
|
+
context = Moxml.new
|
|
208
|
+
context.config.adapter = :ox
|
|
209
|
+
|
|
210
|
+
doc = context.parse(xml)
|
|
211
|
+
|
|
212
|
+
# Check if complex operations needed
|
|
213
|
+
if needs_complex_xpath?(doc)
|
|
214
|
+
# Switch to full-featured adapter
|
|
215
|
+
context.config.adapter = :nokogiri
|
|
216
|
+
doc = context.parse(xml)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
doc
|
|
220
|
+
end
|
|
221
|
+
----
|
|
222
|
+
|
|
223
|
+
=== Configuration validation
|
|
224
|
+
|
|
225
|
+
Verify configuration is correct:
|
|
226
|
+
|
|
227
|
+
[source,ruby]
|
|
228
|
+
----
|
|
229
|
+
context = Moxml.new
|
|
230
|
+
|
|
231
|
+
# Check adapter loaded
|
|
232
|
+
puts context.config.adapter.name
|
|
233
|
+
# => "Moxml::Adapter::Nokogiri"
|
|
234
|
+
|
|
235
|
+
# Verify adapter available
|
|
236
|
+
begin
|
|
237
|
+
context.config.adapter = :missing_adapter
|
|
238
|
+
rescue Moxml::AdapterError => e
|
|
239
|
+
puts "Adapter not available: #{e.message}"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Test parsing works
|
|
243
|
+
test_doc = context.parse('<root/>')
|
|
244
|
+
puts "Configuration valid" if test_doc.root
|
|
245
|
+
----
|
|
246
|
+
|
|
247
|
+
=== See also
|
|
248
|
+
|
|
249
|
+
* link:adapters/[Adapters] - Adapter-specific documentation
|
|
250
|
+
* link:installation[Installation] - Setting up adapters
|
|
251
|
+
* link:../guides/adapter-switching[Adapter switching guide]
|