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,343 @@
1
+ ---
2
+ title: Builder pattern
3
+ parent: Overview
4
+ nav_order: 5
5
+ ---
6
+
7
+ == Builder pattern
8
+
9
+ === Purpose
10
+
11
+ Learn how to use Moxml's builder pattern to create XML documents with a clean,
12
+ Ruby-idiomatic DSL that makes complex XML structures easy to construct and
13
+ maintain.
14
+
15
+ === Prerequisites
16
+
17
+ * Moxml installed
18
+ * Familiarity with link:basic-usage[basic XML operations]
19
+
20
+ === Step 1: Basic builder usage
21
+
22
+ Create simple documents with the builder:
23
+
24
+ [source,ruby]
25
+ ----
26
+ require 'moxml'
27
+
28
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
29
+ xml.library do
30
+ xml.book do
31
+ xml.title "Ruby Programming"
32
+ xml.author "Jane Smith"
33
+ end
34
+ end
35
+ end
36
+
37
+ puts doc.to_xml(indent: 2)
38
+ ----
39
+
40
+ Output:
41
+
42
+ [source,xml]
43
+ ----
44
+ <library>
45
+ <book>
46
+ <title>Ruby Programming</title>
47
+ <author>Jane Smith</author>
48
+ </book>
49
+ </library>
50
+ ----
51
+
52
+ === Step 2: Add XML declaration
53
+
54
+ Include XML declaration:
55
+
56
+ [source,ruby]
57
+ ----
58
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
59
+ xml.declaration version: "1.0", encoding: "UTF-8"
60
+
61
+ xml.library do
62
+ xml.book "Ruby Programming"
63
+ end
64
+ end
65
+ ----
66
+
67
+ Output:
68
+
69
+ [source,xml]
70
+ ----
71
+ <?xml version="1.0" encoding="UTF-8"?>
72
+ <library>
73
+ <book>Ruby Programming</book>
74
+ </library>
75
+ ----
76
+
77
+ === Step 3: Add attributes
78
+
79
+ Set element attributes in the builder:
80
+
81
+ [source,ruby]
82
+ ----
83
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
84
+ xml.library location: "Main", established: "2020" do
85
+ xml.book id: "1", category: "programming" do
86
+ xml.title "Ruby Basics"
87
+ xml.author "Jane Smith"
88
+ xml.price currency: "USD", "29.99"
89
+ end
90
+ end
91
+ end
92
+ ----
93
+
94
+ Output:
95
+
96
+ [source,xml]
97
+ ----
98
+ <library location="Main" established="2020">
99
+ <book id="1" category="programming">
100
+ <title>Ruby Basics</title>
101
+ <author>Jane Smith</author>
102
+ <price currency="USD">29.99</price>
103
+ </book>
104
+ </library>
105
+ ----
106
+
107
+ === Step 4: Nested structures
108
+
109
+ Create complex nested documents:
110
+
111
+ [source,ruby]
112
+ ----
113
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
114
+ xml.declaration version: "1.0", encoding: "UTF-8"
115
+
116
+ xml.library do
117
+ xml.section name: "programming" do
118
+ xml.book id: "1" do
119
+ xml.title "Ruby Basics"
120
+ xml.author "Jane Smith"
121
+ xml.chapters do
122
+ xml.chapter number: "1", "Introduction"
123
+ xml.chapter number: "2", "Getting Started"
124
+ xml.chapter number: "3", "Advanced Topics"
125
+ end
126
+ end
127
+ end
128
+
129
+ xml.section name: "fiction" do
130
+ xml.book id: "2" do
131
+ xml.title "Ruby Story"
132
+ xml.author "John Doe"
133
+ end
134
+ end
135
+ end
136
+ end
137
+ ----
138
+
139
+ === Step 5: Add comments and special content
140
+
141
+ Include comments, CDATA, and processing instructions:
142
+
143
+ [source,ruby]
144
+ ----
145
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
146
+ xml.declaration version: "1.0", encoding: "UTF-8"
147
+
148
+ # Add processing instruction
149
+ xml.processing_instruction "xml-stylesheet",
150
+ 'type="text/xsl" href="style.xsl"'
151
+
152
+ xml.data do
153
+ # Add comment
154
+ xml.comment "This section contains book data"
155
+
156
+ xml.book do
157
+ xml.title "Ruby Programming"
158
+
159
+ # Add CDATA for raw content
160
+ xml.cdata "<raw>HTML content</raw>"
161
+
162
+ xml.description do
163
+ xml.cdata "Contains <em>emphasis</em> and other markup"
164
+ end
165
+ end
166
+ end
167
+ end
168
+ ----
169
+
170
+ === Step 6: Builder with namespaces
171
+
172
+ Create namespaced elements with the builder:
173
+
174
+ [source,ruby]
175
+ ----
176
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
177
+ xml.declaration version: "1.0", encoding: "UTF-8"
178
+
179
+ xml.element 'library',
180
+ 'xmlns' => 'http://example.org/library',
181
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/' do
182
+
183
+ xml.book do
184
+ xml.element 'dc:title', 'Ruby Programming'
185
+ xml.element 'dc:creator', 'Jane Smith'
186
+ xml.element 'dc:date', '2024'
187
+ end
188
+ end
189
+ end
190
+ ----
191
+
192
+ === Step 7: Dynamic content generation
193
+
194
+ Generate XML from data structures:
195
+
196
+ [source,ruby]
197
+ ----
198
+ books_data = [
199
+ { id: 1, title: 'Ruby Basics', author: 'Smith', price: 29.99 },
200
+ { id: 2, title: 'Advanced Ruby', author: 'Doe', price: 39.99 },
201
+ { id: 3, title: 'Ruby Patterns', author: 'Johnson', price: 34.99 }
202
+ ]
203
+
204
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
205
+ xml.declaration version: "1.0", encoding: "UTF-8"
206
+
207
+ xml.library do
208
+ books_data.each do |book_data|
209
+ xml.book id: book_data[:id] do
210
+ xml.title book_data[:title]
211
+ xml.author book_data[:author]
212
+ xml.price book_data[:price].to_s
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ puts doc.to_xml(indent: 2)
219
+ ----
220
+
221
+ === Step 8: Conditional builder logic
222
+
223
+ Add elements conditionally:
224
+
225
+ [source,ruby]
226
+ ----
227
+ book_data = {
228
+ title: 'Ruby Programming',
229
+ author: 'Jane Smith',
230
+ isbn: '978-0-123456-78-9',
231
+ edition: nil, # Not set
232
+ price: 29.99
233
+ }
234
+
235
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
236
+ xml.book do
237
+ xml.title book_data[:title]
238
+ xml.author book_data[:author]
239
+
240
+ # Conditional elements
241
+ if book_data[:isbn]
242
+ xml.isbn book_data[:isbn]
243
+ end
244
+
245
+ if book_data[:edition]
246
+ xml.edition book_data[:edition]
247
+ end
248
+
249
+ xml.price book_data[:price].to_s
250
+ end
251
+ end
252
+ ----
253
+
254
+ === Builder vs direct manipulation
255
+
256
+ Compare the two approaches:
257
+
258
+ **Using Builder (preferred for creation):**
259
+
260
+ [source,ruby]
261
+ ----
262
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
263
+ xml.library do
264
+ xml.book id: "1" do
265
+ xml.title "Ruby Programming"
266
+ end
267
+ end
268
+ end
269
+ ----
270
+
271
+ **Direct manipulation (preferred for modification):**
272
+
273
+ [source,ruby]
274
+ ----
275
+ doc = Moxml.new.create_document
276
+ root = doc.create_element('library')
277
+ doc.add_child(root)
278
+
279
+ book = doc.create_element('book')
280
+ book['id'] = '1'
281
+ root.add_child(book)
282
+
283
+ title = doc.create_element('title')
284
+ title.text = 'Ruby Programming'
285
+ book.add_child(title)
286
+ ----
287
+
288
+ === Best practices
289
+
290
+ . **Use builder for new documents** - cleaner and more maintainable
291
+ . **Use direct manipulation for modifications** - more control
292
+ . **Extract complex builders** into methods for reusability
293
+ . **Validate generated XML** after building
294
+ . **Keep builders focused** - one logical structure per builder
295
+
296
+ === Common patterns
297
+
298
+ ==== Reusable builder methods
299
+
300
+ [source,ruby]
301
+ ----
302
+ def build_book(xml, book_data)
303
+ xml.book id: book_data[:id] do
304
+ xml.title book_data[:title]
305
+ xml.author book_data[:author]
306
+ xml.price book_data[:price].to_s
307
+ end
308
+ end
309
+
310
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
311
+ xml.library do
312
+ books_data.each { |book| build_book(xml, book) }
313
+ end
314
+ end
315
+ ----
316
+
317
+ ==== Mixed content
318
+
319
+ [source,ruby]
320
+ ----
321
+ doc = Moxml::Builder.build(Moxml.new) do |xml|
322
+ xml.article do
323
+ xml.title "Introduction"
324
+ xml.para do
325
+ xml.text "This is "
326
+ xml.emphasis "important"
327
+ xml.text " content."
328
+ end
329
+ end
330
+ end
331
+ ----
332
+
333
+ === Next steps
334
+
335
+ * link:../guides/creating-documents[Creating documents guide] - More document
336
+ creation patterns
337
+ * link:working-with-elements[Working with elements] - Element manipulation
338
+ * link:../references/builder-api[Builder API reference]
339
+
340
+ === See also
341
+
342
+ * link:../references/document-api[Document API] - Direct manipulation methods
343
+ * link:namespace-handling[Namespace handling] - Namespaced builders
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: Overview
3
+ nav_order: 1
4
+ ---
5
+
6
+ == Tutorials
7
+
8
+ Step-by-step learning paths to master Moxml's features and capabilities.
9
+
10
+ === Getting started
11
+
12
+ link:basic-usage[Basic usage]::
13
+ Learn the fundamentals of parsing, creating, and manipulating XML documents
14
+ with Moxml.
15
+
16
+ link:working-with-elements[Working with elements]::
17
+ Master element creation, manipulation, and attribute handling.
18
+
19
+ link:xpath-queries[XPath queries]::
20
+ Learn how to query XML documents effectively using XPath expressions.
21
+
22
+ === Advanced topics
23
+
24
+ link:namespace-handling[Namespace handling]::
25
+ Work with XML namespaces including prefixes, URIs, and namespace-aware
26
+ queries.
27
+
28
+ link:builder-pattern[Builder pattern]::
29
+ Use Moxml's DSL to create complex XML documents cleanly and efficiently.
30
+
31
+ link:adapter-switching[Adapter switching]::
32
+ Understand how to choose and switch between different XML adapters based on
33
+ your requirements.
@@ -0,0 +1,325 @@
1
+ ---
2
+ title: Namespace handling
3
+ parent: Overview
4
+ nav_order: 4
5
+ ---
6
+
7
+ == Namespace handling
8
+
9
+ === Purpose
10
+
11
+ Learn how to work with XML namespaces in Moxml including creating namespaced
12
+ elements, querying with namespace prefixes, and understanding namespace
13
+ inheritance.
14
+
15
+ === Prerequisites
16
+
17
+ * Understanding of XML namespace concepts
18
+ * Moxml installed with an adapter supporting namespaces
19
+ * Familiarity with link:xpath-queries[XPath queries]
20
+
21
+ === Step 1: Understanding XML namespaces
22
+
23
+ XML namespaces prevent element name conflicts:
24
+
25
+ [source,xml]
26
+ ----
27
+ <!-- Without namespaces - ambiguous -->
28
+ <title>Book Title</title>
29
+ <title>Page Title</title>
30
+
31
+ <!-- With namespaces - clear distinction -->
32
+ <book:title xmlns:book="http://example.org/book">Book Title</book:title>
33
+ <page:title xmlns:page="http://example.org/page">Page Title</page:title>
34
+ ----
35
+
36
+ In Moxml:
37
+
38
+ [source,ruby]
39
+ ----
40
+ xml = <<~XML
41
+ <library xmlns:dc="http://purl.org/dc/elements/1.1/">
42
+ <book>
43
+ <dc:title>Ruby Programming</dc:title>
44
+ <dc:creator>Jane Smith</dc:creator>
45
+ </book>
46
+ </library>
47
+ XML
48
+
49
+ doc = Moxml.new.parse(xml)
50
+
51
+ # Namespaces are preserved
52
+ book = doc.at_xpath('//book')
53
+ title = book.children.find { |n| n.name.include?('title') }
54
+
55
+ # Access namespace
56
+ puts title.namespace.uri if title.namespace
57
+ # => "http://purl.org/dc/elements/1.1/"
58
+ ----
59
+
60
+ === Step 2: Create namespaced elements
61
+
62
+ Add namespaces to elements:
63
+
64
+ [source,ruby]
65
+ ----
66
+ doc = Moxml.new.create_document
67
+
68
+ # Create root with default namespace
69
+ root = doc.create_element('library')
70
+ root.add_namespace(nil, 'http://example.org/library')
71
+ doc.add_child(root)
72
+
73
+ # Create element with prefix namespace
74
+ book = doc.create_element('book')
75
+ book.add_namespace('dc', 'http://purl.org/dc/elements/1.1/')
76
+ root.add_child(book)
77
+
78
+ # Create namespaced child elements
79
+ title = doc.create_element('dc:title')
80
+ title.text = 'Ruby Programming'
81
+ book.add_child(title)
82
+
83
+ creator = doc.create_element('dc:creator')
84
+ creator.text = 'Jane Smith'
85
+ book.add_child(creator)
86
+
87
+ puts doc.to_xml(indent: 2)
88
+ ----
89
+
90
+ Output:
91
+
92
+ [source,xml]
93
+ ----
94
+ <library xmlns="http://example.org/library">
95
+ <book xmlns:dc="http://purl.org/dc/elements/1.1/">
96
+ <dc:title>Ruby Programming</dc:title>
97
+ <dc:creator>Jane Smith</dc:creator>
98
+ </book>
99
+ </library>
100
+ ----
101
+
102
+ === Step 3: Query with namespaces
103
+
104
+ Use namespace mappings in XPath queries:
105
+
106
+ [source,ruby]
107
+ ----
108
+ xml = <<~XML
109
+ <library xmlns="http://example.org/library"
110
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
111
+ xmlns:isbn="http://example.org/isbn">
112
+ <book isbn:value="978-0-123456-78-9">
113
+ <dc:title>Ruby Programming</dc:title>
114
+ <dc:creator>Jane Smith</dc:creator>
115
+ </book>
116
+ </library>
117
+ XML
118
+
119
+ doc = Moxml.new.parse(xml)
120
+
121
+ # Define namespace prefixes for XPath
122
+ namespaces = {
123
+ 'lib' => 'http://example.org/library',
124
+ 'dc' => 'http://purl.org/dc/elements/1.1/',
125
+ 'isbn' => 'http://example.org/isbn'
126
+ }
127
+
128
+ # Query with namespace prefixes
129
+ books = doc.xpath('//lib:book', namespaces)
130
+ titles = doc.xpath('//dc:title', namespaces)
131
+ creators = doc.xpath('//dc:creator', namespaces)
132
+
133
+ puts books.length # => 1
134
+ puts titles.first.text # => "Ruby Programming"
135
+ puts creators.first.text # => "Jane Smith"
136
+
137
+ # Query namespaced attributes
138
+ book_with_isbn = doc.at_xpath('//lib:book[@isbn:value]', namespaces)
139
+ puts book_with_isbn['isbn:value'] # => "978-0-123456-78-9"
140
+ ----
141
+
142
+ === Step 4: Default namespaces
143
+
144
+ Handle default (unprefixed) namespaces:
145
+
146
+ [source,ruby]
147
+ ----
148
+ xml = <<~XML
149
+ <library xmlns="http://example.org/library">
150
+ <book>
151
+ <title>Ruby Programming</title>
152
+ </book>
153
+ </library>
154
+ XML
155
+
156
+ doc = Moxml.new.parse(xml)
157
+
158
+ # Map default namespace to a prefix for XPath
159
+ namespaces = {
160
+ 'lib' => 'http://example.org/library'
161
+ }
162
+
163
+ # Query elements in default namespace
164
+ books = doc.xpath('//lib:book', namespaces)
165
+ titles = doc.xpath('//lib:title', namespaces)
166
+
167
+ puts books.length # => 1
168
+ puts titles.first.text # => "Ruby Programming"
169
+ ----
170
+
171
+ === Step 5: Multiple namespaces
172
+
173
+ Work with documents using multiple namespaces:
174
+
175
+ [source,ruby]
176
+ ----
177
+ xml = <<~XML
178
+ <rss xmlns:content="http://purl.org/rss/1.0/modules/content/"
179
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
180
+ <item>
181
+ <title>Article Title</title>
182
+ <dc:creator>Author Name</dc:creator>
183
+ <content:encoded><![CDATA[Article content]]></content:encoded>
184
+ </item>
185
+ </rss>
186
+ XML
187
+
188
+ doc = Moxml.new.parse(xml)
189
+
190
+ # Map all namespaces
191
+ ns = {
192
+ 'content' => 'http://purl.org/rss/1.0/modules/content/',
193
+ 'dc' => 'http://purl.org/dc/elements/1.1/'
194
+ }
195
+
196
+ # Query across namespaces
197
+ items = doc.xpath('//item')
198
+ creators = doc.xpath('//dc:creator', ns)
199
+ content = doc.xpath('//content:encoded', ns)
200
+
201
+ puts creators.first.text # => "Author Name"
202
+ puts content.first.text # => "Article content"
203
+ ----
204
+
205
+ === Step 6: Namespace inheritance
206
+
207
+ Child elements inherit parent namespaces:
208
+
209
+ [source,ruby]
210
+ ----
211
+ doc = Moxml.new.create_document
212
+
213
+ # Parent with namespace
214
+ parent = doc.create_element('parent')
215
+ parent.add_namespace('ex', 'http://example.org')
216
+ doc.add_child(parent)
217
+
218
+ # Child inherits namespace
219
+ child = doc.create_element('ex:child')
220
+ child.text = 'Inherits ex namespace'
221
+ parent.add_child(child)
222
+
223
+ # Grandchild also inherits
224
+ grandchild = doc.create_element('ex:grandchild')
225
+ grandchild.text = 'Also inherits'
226
+ child.add_child(grandchild)
227
+
228
+ # Query with inherited namespace
229
+ ns = { 'ex' => 'http://example.org' }
230
+ descendants = doc.xpath('//ex:*', ns)
231
+ puts descendants.length # => 3 (parent, child, grandchild)
232
+ ----
233
+
234
+ === Step 7: Namespace scope and context
235
+
236
+ Understand namespace scope:
237
+
238
+ [source,ruby]
239
+ ----
240
+ xml = <<~XML
241
+ <root xmlns:a="http://a.org">
242
+ <a:parent>
243
+ <a:child id="1"/>
244
+ <b:child xmlns:b="http://b.org" id="2"/>
245
+ </a:parent>
246
+ </root>
247
+ XML
248
+
249
+ doc = Moxml.new.parse(xml)
250
+
251
+ # Query with appropriate namespace scope
252
+ ns_a = { 'a' => 'http://a.org' }
253
+ ns_b = { 'b' => 'http://b.org' }
254
+
255
+ a_children = doc.xpath('//a:child', ns_a)
256
+ b_children = doc.xpath('//b:child', ns_b)
257
+
258
+ puts a_children.length # => 1 (only <a:child>)
259
+ puts b_children.length # => 1 (only <b:child>)
260
+
261
+ # Both namespaces in one query
262
+ ns_both = ns_a.merge(ns_b)
263
+ all_children = doc.xpath('//a:child | //b:child', ns_both)
264
+ puts all_children.length # => 2
265
+ ----
266
+
267
+ === Adapter compatibility
268
+
269
+ **Full namespace support:**
270
+
271
+ * link:../pages/adapters/nokogiri[Nokogiri] - ✅ All features
272
+ * link:../pages/adapters/libxml[LibXML] - ✅ All features
273
+ * link:../pages/adapters/oga[Oga] - ✅ All features
274
+
275
+ **Limited namespace support:**
276
+
277
+ * link:../pages/adapters/rexml[REXML] - ⚠️ No namespace XPath
278
+ * link:../pages/adapters/ox[Ox] - ⚠️ Basic only, no XPath
279
+
280
+ === Troubleshooting
281
+
282
+ **Namespace XPath not working:**
283
+
284
+ [source,ruby]
285
+ ----
286
+ # If namespace query returns nothing, check:
287
+
288
+ # 1. Namespace mapping is correct
289
+ puts doc.root.namespace.uri # Verify actual URI
290
+
291
+ # 2. Using correct prefix in XPath
292
+ # Must match your mapping, not the document's prefix
293
+
294
+ # 3. Adapter supports namespace XPath
295
+ puts context.config.adapter.name
296
+ # REXML and Ox have limited support
297
+ ----
298
+
299
+ **Namespace not inherited:**
300
+
301
+ [source,ruby]
302
+ ----
303
+ # Ox doesn't support namespace inheritance
304
+ # Workaround: explicitly set namespace on each element
305
+ child.add_namespace('ex', 'http://example.org')
306
+ ----
307
+
308
+ === Best practices
309
+
310
+ . **Always define namespace mappings** for XPath queries
311
+ . **Use consistent prefix names** across your application
312
+ . **Check adapter compatibility** for namespace features
313
+ . **Test namespace operations** with your chosen adapter
314
+ . **Document namespace URIs** used in your XML
315
+
316
+ === Next steps
317
+
318
+ * link:builder-pattern[Builder pattern] - Create complex namespaced documents
319
+ * link:../guides/namespace-management[Namespace management guide]
320
+ * link:../references/namespace-api[Namespace API reference]
321
+
322
+ === See also
323
+
324
+ * link:../pages/compatibility[Compatibility matrix] - Namespace support comparison
325
+ * link:../guides/xpath-queries[XPath queries guide] - Advanced namespace queries