moxml 0.1.7 → 0.1.9

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