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.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-repos.json +5 -0
  3. data/.github/workflows/dependent-tests.yml +20 -0
  4. data/.github/workflows/docs.yml +59 -0
  5. data/.github/workflows/rake.yml +10 -10
  6. data/.github/workflows/release.yml +5 -3
  7. data/.gitignore +37 -0
  8. data/.rubocop.yml +15 -7
  9. data/.rubocop_todo.yml +238 -40
  10. data/Gemfile +14 -9
  11. data/LICENSE.md +6 -2
  12. data/README.adoc +535 -373
  13. data/Rakefile +53 -0
  14. data/benchmarks/.gitignore +6 -0
  15. data/benchmarks/generate_report.rb +550 -0
  16. data/docs/Gemfile +13 -0
  17. data/docs/_config.yml +138 -0
  18. data/docs/_guides/advanced-features.adoc +87 -0
  19. data/docs/_guides/development-testing.adoc +165 -0
  20. data/docs/_guides/index.adoc +45 -0
  21. data/docs/_guides/modifying-xml.adoc +293 -0
  22. data/docs/_guides/parsing-xml.adoc +231 -0
  23. data/docs/_guides/sax-parsing.adoc +603 -0
  24. data/docs/_guides/working-with-documents.adoc +118 -0
  25. data/docs/_pages/adapter-compatibility.adoc +369 -0
  26. data/docs/_pages/adapters/headed-ox.adoc +237 -0
  27. data/docs/_pages/adapters/index.adoc +98 -0
  28. data/docs/_pages/adapters/libxml.adoc +286 -0
  29. data/docs/_pages/adapters/nokogiri.adoc +252 -0
  30. data/docs/_pages/adapters/oga.adoc +292 -0
  31. data/docs/_pages/adapters/ox.adoc +55 -0
  32. data/docs/_pages/adapters/rexml.adoc +293 -0
  33. data/docs/_pages/best-practices.adoc +430 -0
  34. data/docs/_pages/compatibility.adoc +468 -0
  35. data/docs/_pages/configuration.adoc +251 -0
  36. data/docs/_pages/error-handling.adoc +350 -0
  37. data/docs/_pages/headed-ox-limitations.adoc +558 -0
  38. data/docs/_pages/headed-ox.adoc +1025 -0
  39. data/docs/_pages/index.adoc +35 -0
  40. data/docs/_pages/installation.adoc +141 -0
  41. data/docs/_pages/node-api-reference.adoc +50 -0
  42. data/docs/_pages/performance.adoc +36 -0
  43. data/docs/_pages/quick-start.adoc +244 -0
  44. data/docs/_pages/thread-safety.adoc +29 -0
  45. data/docs/_references/document-api.adoc +408 -0
  46. data/docs/_references/index.adoc +48 -0
  47. data/docs/_tutorials/basic-usage.adoc +268 -0
  48. data/docs/_tutorials/builder-pattern.adoc +343 -0
  49. data/docs/_tutorials/index.adoc +33 -0
  50. data/docs/_tutorials/namespace-handling.adoc +325 -0
  51. data/docs/_tutorials/xpath-queries.adoc +359 -0
  52. data/docs/index.adoc +122 -0
  53. data/examples/README.md +124 -0
  54. data/examples/api_client/README.md +424 -0
  55. data/examples/api_client/api_client.rb +394 -0
  56. data/examples/api_client/example_response.xml +48 -0
  57. data/examples/headed_ox_example/README.md +90 -0
  58. data/examples/headed_ox_example/headed_ox_demo.rb +71 -0
  59. data/examples/rss_parser/README.md +194 -0
  60. data/examples/rss_parser/example_feed.xml +93 -0
  61. data/examples/rss_parser/rss_parser.rb +189 -0
  62. data/examples/sax_parsing/README.md +50 -0
  63. data/examples/sax_parsing/data_extractor.rb +75 -0
  64. data/examples/sax_parsing/example.xml +21 -0
  65. data/examples/sax_parsing/large_file.rb +78 -0
  66. data/examples/sax_parsing/simple_parser.rb +55 -0
  67. data/examples/web_scraper/README.md +352 -0
  68. data/examples/web_scraper/example_page.html +201 -0
  69. data/examples/web_scraper/web_scraper.rb +312 -0
  70. data/lib/moxml/adapter/base.rb +107 -28
  71. data/lib/moxml/adapter/customized_libxml/cdata.rb +28 -0
  72. data/lib/moxml/adapter/customized_libxml/comment.rb +24 -0
  73. data/lib/moxml/adapter/customized_libxml/declaration.rb +85 -0
  74. data/lib/moxml/adapter/customized_libxml/element.rb +39 -0
  75. data/lib/moxml/adapter/customized_libxml/node.rb +44 -0
  76. data/lib/moxml/adapter/customized_libxml/processing_instruction.rb +31 -0
  77. data/lib/moxml/adapter/customized_libxml/text.rb +27 -0
  78. data/lib/moxml/adapter/customized_oga/xml_generator.rb +1 -1
  79. data/lib/moxml/adapter/customized_ox/attribute.rb +28 -1
  80. data/lib/moxml/adapter/customized_rexml/formatter.rb +11 -6
  81. data/lib/moxml/adapter/headed_ox.rb +161 -0
  82. data/lib/moxml/adapter/libxml.rb +1548 -0
  83. data/lib/moxml/adapter/nokogiri.rb +121 -9
  84. data/lib/moxml/adapter/oga.rb +123 -12
  85. data/lib/moxml/adapter/ox.rb +282 -26
  86. data/lib/moxml/adapter/rexml.rb +127 -20
  87. data/lib/moxml/adapter.rb +21 -4
  88. data/lib/moxml/attribute.rb +6 -0
  89. data/lib/moxml/builder.rb +40 -4
  90. data/lib/moxml/config.rb +8 -3
  91. data/lib/moxml/context.rb +39 -1
  92. data/lib/moxml/doctype.rb +13 -1
  93. data/lib/moxml/document.rb +39 -6
  94. data/lib/moxml/document_builder.rb +27 -5
  95. data/lib/moxml/element.rb +71 -2
  96. data/lib/moxml/error.rb +175 -6
  97. data/lib/moxml/node.rb +94 -3
  98. data/lib/moxml/node_set.rb +34 -0
  99. data/lib/moxml/sax/block_handler.rb +194 -0
  100. data/lib/moxml/sax/element_handler.rb +124 -0
  101. data/lib/moxml/sax/handler.rb +113 -0
  102. data/lib/moxml/sax.rb +31 -0
  103. data/lib/moxml/version.rb +1 -1
  104. data/lib/moxml/xml_utils/encoder.rb +4 -4
  105. data/lib/moxml/xml_utils.rb +7 -4
  106. data/lib/moxml/xpath/ast/node.rb +159 -0
  107. data/lib/moxml/xpath/cache.rb +91 -0
  108. data/lib/moxml/xpath/compiler.rb +1768 -0
  109. data/lib/moxml/xpath/context.rb +26 -0
  110. data/lib/moxml/xpath/conversion.rb +124 -0
  111. data/lib/moxml/xpath/engine.rb +52 -0
  112. data/lib/moxml/xpath/errors.rb +101 -0
  113. data/lib/moxml/xpath/lexer.rb +304 -0
  114. data/lib/moxml/xpath/parser.rb +485 -0
  115. data/lib/moxml/xpath/ruby/generator.rb +269 -0
  116. data/lib/moxml/xpath/ruby/node.rb +193 -0
  117. data/lib/moxml/xpath.rb +37 -0
  118. data/lib/moxml.rb +5 -2
  119. data/moxml.gemspec +3 -1
  120. data/old-specs/moxml/adapter/customized_libxml/.gitkeep +6 -0
  121. data/spec/consistency/README.md +77 -0
  122. data/spec/{moxml/examples/adapter_spec.rb → consistency/adapter_parity_spec.rb} +4 -4
  123. data/spec/examples/README.md +75 -0
  124. data/spec/{support/shared_examples/examples/attribute.rb → examples/attribute_examples_spec.rb} +1 -1
  125. data/spec/{support/shared_examples/examples/basic_usage.rb → examples/basic_usage_spec.rb} +2 -2
  126. data/spec/{support/shared_examples/examples/namespace.rb → examples/namespace_examples_spec.rb} +3 -3
  127. data/spec/{support/shared_examples/examples/readme_examples.rb → examples/readme_examples_spec.rb} +6 -4
  128. data/spec/{support/shared_examples/examples/xpath.rb → examples/xpath_examples_spec.rb} +10 -6
  129. data/spec/integration/README.md +71 -0
  130. data/spec/{moxml/all_with_adapters_spec.rb → integration/all_adapters_spec.rb} +3 -2
  131. data/spec/integration/headed_ox_integration_spec.rb +326 -0
  132. data/spec/{support → integration}/shared_examples/edge_cases.rb +37 -10
  133. data/spec/integration/shared_examples/high_level/.gitkeep +0 -0
  134. data/spec/{support/shared_examples/context.rb → integration/shared_examples/high_level/context_behavior.rb} +2 -1
  135. data/spec/{support/shared_examples/integration.rb → integration/shared_examples/integration_workflows.rb} +23 -6
  136. data/spec/integration/shared_examples/node_wrappers/.gitkeep +0 -0
  137. data/spec/{support/shared_examples/cdata.rb → integration/shared_examples/node_wrappers/cdata_behavior.rb} +6 -1
  138. data/spec/{support/shared_examples/comment.rb → integration/shared_examples/node_wrappers/comment_behavior.rb} +2 -1
  139. data/spec/{support/shared_examples/declaration.rb → integration/shared_examples/node_wrappers/declaration_behavior.rb} +5 -2
  140. data/spec/{support/shared_examples/doctype.rb → integration/shared_examples/node_wrappers/doctype_behavior.rb} +2 -2
  141. data/spec/{support/shared_examples/document.rb → integration/shared_examples/node_wrappers/document_behavior.rb} +1 -1
  142. data/spec/{support/shared_examples/node.rb → integration/shared_examples/node_wrappers/node_behavior.rb} +9 -2
  143. data/spec/{support/shared_examples/node_set.rb → integration/shared_examples/node_wrappers/node_set_behavior.rb} +1 -18
  144. data/spec/{support/shared_examples/processing_instruction.rb → integration/shared_examples/node_wrappers/processing_instruction_behavior.rb} +6 -2
  145. data/spec/moxml/README.md +41 -0
  146. data/spec/moxml/adapter/.gitkeep +0 -0
  147. data/spec/moxml/adapter/README.md +61 -0
  148. data/spec/moxml/adapter/base_spec.rb +27 -0
  149. data/spec/moxml/adapter/headed_ox_spec.rb +311 -0
  150. data/spec/moxml/adapter/libxml_spec.rb +14 -0
  151. data/spec/moxml/adapter/ox_spec.rb +9 -8
  152. data/spec/moxml/adapter/shared_examples/.gitkeep +0 -0
  153. data/spec/{support/shared_examples/xml_adapter.rb → moxml/adapter/shared_examples/adapter_contract.rb} +39 -12
  154. data/spec/moxml/adapter_spec.rb +16 -0
  155. data/spec/moxml/attribute_spec.rb +30 -0
  156. data/spec/moxml/builder_spec.rb +33 -0
  157. data/spec/moxml/cdata_spec.rb +31 -0
  158. data/spec/moxml/comment_spec.rb +31 -0
  159. data/spec/moxml/config_spec.rb +3 -3
  160. data/spec/moxml/context_spec.rb +28 -0
  161. data/spec/moxml/declaration_spec.rb +36 -0
  162. data/spec/moxml/doctype_spec.rb +33 -0
  163. data/spec/moxml/document_builder_spec.rb +30 -0
  164. data/spec/moxml/document_spec.rb +105 -0
  165. data/spec/moxml/element_spec.rb +143 -0
  166. data/spec/moxml/error_spec.rb +266 -22
  167. data/spec/{moxml_spec.rb → moxml/moxml_spec.rb} +9 -9
  168. data/spec/moxml/namespace_spec.rb +32 -0
  169. data/spec/moxml/node_set_spec.rb +39 -0
  170. data/spec/moxml/node_spec.rb +37 -0
  171. data/spec/moxml/processing_instruction_spec.rb +34 -0
  172. data/spec/moxml/sax_spec.rb +1067 -0
  173. data/spec/moxml/text_spec.rb +31 -0
  174. data/spec/moxml/version_spec.rb +14 -0
  175. data/spec/moxml/xml_utils/.gitkeep +0 -0
  176. data/spec/moxml/xml_utils/encoder_spec.rb +27 -0
  177. data/spec/moxml/xml_utils_spec.rb +49 -0
  178. data/spec/moxml/xpath/ast/node_spec.rb +83 -0
  179. data/spec/moxml/xpath/axes_spec.rb +296 -0
  180. data/spec/moxml/xpath/cache_spec.rb +358 -0
  181. data/spec/moxml/xpath/compiler_spec.rb +406 -0
  182. data/spec/moxml/xpath/context_spec.rb +210 -0
  183. data/spec/moxml/xpath/conversion_spec.rb +365 -0
  184. data/spec/moxml/xpath/fixtures/sample.xml +25 -0
  185. data/spec/moxml/xpath/functions/boolean_functions_spec.rb +114 -0
  186. data/spec/moxml/xpath/functions/node_functions_spec.rb +145 -0
  187. data/spec/moxml/xpath/functions/numeric_functions_spec.rb +164 -0
  188. data/spec/moxml/xpath/functions/position_functions_spec.rb +93 -0
  189. data/spec/moxml/xpath/functions/special_functions_spec.rb +89 -0
  190. data/spec/moxml/xpath/functions/string_functions_spec.rb +381 -0
  191. data/spec/moxml/xpath/lexer_spec.rb +488 -0
  192. data/spec/moxml/xpath/parser_integration_spec.rb +210 -0
  193. data/spec/moxml/xpath/parser_spec.rb +364 -0
  194. data/spec/moxml/xpath/ruby/generator_spec.rb +421 -0
  195. data/spec/moxml/xpath/ruby/node_spec.rb +291 -0
  196. data/spec/moxml/xpath_capabilities_spec.rb +199 -0
  197. data/spec/moxml/xpath_spec.rb +77 -0
  198. data/spec/performance/README.md +83 -0
  199. data/spec/performance/benchmark_spec.rb +64 -0
  200. data/spec/{support/shared_examples/examples/memory.rb → performance/memory_usage_spec.rb} +3 -1
  201. data/spec/{support/shared_examples/examples/thread_safety.rb → performance/thread_safety_spec.rb} +3 -1
  202. data/spec/performance/xpath_benchmark_spec.rb +259 -0
  203. data/spec/spec_helper.rb +58 -1
  204. data/spec/support/xml_matchers.rb +1 -1
  205. metadata +176 -34
  206. data/spec/support/shared_examples/examples/benchmark_spec.rb +0 -51
  207. /data/spec/{support/shared_examples/builder.rb → integration/shared_examples/high_level/builder_behavior.rb} +0 -0
  208. /data/spec/{support/shared_examples/document_builder.rb → integration/shared_examples/high_level/document_builder_behavior.rb} +0 -0
  209. /data/spec/{support/shared_examples/attribute.rb → integration/shared_examples/node_wrappers/attribute_behavior.rb} +0 -0
  210. /data/spec/{support/shared_examples/element.rb → integration/shared_examples/node_wrappers/element_behavior.rb} +0 -0
  211. /data/spec/{support/shared_examples/namespace.rb → integration/shared_examples/node_wrappers/namespace_behavior.rb} +0 -0
  212. /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]