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.
- 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 +224 -43
- 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 +51 -0
- data/docs/_guides/modifying-xml.adoc +292 -0
- data/docs/_guides/parsing-xml.adoc +230 -0
- data/docs/_guides/sax-parsing.adoc +603 -0
- data/docs/_guides/working-with-documents.adoc +118 -0
- data/docs/_guides/xml-declaration.adoc +450 -0
- data/docs/_pages/adapter-compatibility.adoc +369 -0
- data/docs/_pages/adapters/headed-ox.adoc +237 -0
- data/docs/_pages/adapters/index.adoc +97 -0
- data/docs/_pages/adapters/libxml.adoc +285 -0
- data/docs/_pages/adapters/nokogiri.adoc +251 -0
- data/docs/_pages/adapters/oga.adoc +291 -0
- data/docs/_pages/adapters/ox.adoc +56 -0
- data/docs/_pages/adapters/rexml.adoc +292 -0
- data/docs/_pages/best-practices.adoc +429 -0
- data/docs/_pages/compatibility.adoc +467 -0
- data/docs/_pages/configuration.adoc +250 -0
- data/docs/_pages/error-handling.adoc +349 -0
- data/docs/_pages/headed-ox-limitations.adoc +574 -0
- data/docs/_pages/headed-ox.adoc +1025 -0
- data/docs/_pages/index.adoc +35 -0
- data/docs/_pages/installation.adoc +140 -0
- data/docs/_pages/node-api-reference.adoc +49 -0
- data/docs/_pages/performance.adoc +35 -0
- data/docs/_pages/quick-start.adoc +243 -0
- data/docs/_pages/thread-safety.adoc +28 -0
- data/docs/_references/document-api.adoc +407 -0
- data/docs/_references/index.adoc +48 -0
- data/docs/_tutorials/basic-usage.adoc +267 -0
- data/docs/_tutorials/builder-pattern.adoc +342 -0
- data/docs/_tutorials/index.adoc +33 -0
- data/docs/_tutorials/namespace-handling.adoc +324 -0
- data/docs/_tutorials/xpath-queries.adoc +358 -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 +13 -8
- data/lib/moxml/adapter/headed_ox.rb +161 -0
- data/lib/moxml/adapter/libxml.rb +1564 -0
- data/lib/moxml/adapter/nokogiri.rb +156 -9
- data/lib/moxml/adapter/oga.rb +190 -15
- data/lib/moxml/adapter/ox.rb +322 -28
- data/lib/moxml/adapter/rexml.rb +157 -28
- 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 +57 -2
- data/lib/moxml/declaration.rb +9 -0
- data/lib/moxml/doctype.rb +13 -1
- data/lib/moxml/document.rb +53 -6
- data/lib/moxml/document_builder.rb +34 -5
- data/lib/moxml/element.rb +71 -2
- data/lib/moxml/error.rb +175 -6
- data/lib/moxml/node.rb +155 -4
- 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 +1770 -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 -5
- 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_preservation_spec.rb +217 -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} +4 -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 +178 -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,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Overview
|
|
3
|
+
nav_order: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Core topics
|
|
7
|
+
|
|
8
|
+
This section covers the fundamental concepts and essential information for
|
|
9
|
+
working with Moxml.
|
|
10
|
+
|
|
11
|
+
=== Topics covered
|
|
12
|
+
|
|
13
|
+
link:installation[Installation]::
|
|
14
|
+
How to install Moxml and select an XML adapter for your needs.
|
|
15
|
+
|
|
16
|
+
link:quick-start[Quick start]::
|
|
17
|
+
Get up and running with Moxml in minutes with practical examples.
|
|
18
|
+
|
|
19
|
+
link:architecture[Architecture]::
|
|
20
|
+
Understand how Moxml's unified interface and adapter system works.
|
|
21
|
+
|
|
22
|
+
link:adapters/[Adapters]::
|
|
23
|
+
Learn about the supported XML libraries and how to choose the right one.
|
|
24
|
+
|
|
25
|
+
link:compatibility[Compatibility]::
|
|
26
|
+
Compare features, performance, and compatibility across adapters.
|
|
27
|
+
|
|
28
|
+
link:configuration[Configuration]::
|
|
29
|
+
Configure Moxml for your application's requirements.
|
|
30
|
+
|
|
31
|
+
link:error-handling[Error handling]::
|
|
32
|
+
Comprehensive guide to Moxml's error classes and debugging.
|
|
33
|
+
|
|
34
|
+
link:best-practices[Best practices]::
|
|
35
|
+
Recommended patterns and practices for using Moxml effectively.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
nav_order: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Installation
|
|
7
|
+
|
|
8
|
+
=== Purpose
|
|
9
|
+
|
|
10
|
+
This guide covers how to install Moxml and set up your chosen XML adapter for
|
|
11
|
+
Ruby applications.
|
|
12
|
+
|
|
13
|
+
=== Requirements
|
|
14
|
+
|
|
15
|
+
* Ruby >= 3.0.0
|
|
16
|
+
* At least one supported XML library (Nokogiri, LibXML, Oga, REXML, or Ox)
|
|
17
|
+
|
|
18
|
+
=== Basic installation
|
|
19
|
+
|
|
20
|
+
Add Moxml and your chosen XML adapter to your Gemfile:
|
|
21
|
+
|
|
22
|
+
[source,ruby]
|
|
23
|
+
----
|
|
24
|
+
# Gemfile
|
|
25
|
+
gem 'moxml'
|
|
26
|
+
|
|
27
|
+
# Choose one or more XML adapters:
|
|
28
|
+
gem 'nokogiri' # Recommended: Fast, widely used
|
|
29
|
+
gem 'libxml-ruby' # Alternative: Native performance
|
|
30
|
+
gem 'oga' # Pure Ruby: No C extensions
|
|
31
|
+
gem 'ox' # Fastest: Best for simple documents
|
|
32
|
+
# REXML is included in Ruby standard library
|
|
33
|
+
----
|
|
34
|
+
|
|
35
|
+
Then install:
|
|
36
|
+
|
|
37
|
+
[source,shell]
|
|
38
|
+
----
|
|
39
|
+
bundle install
|
|
40
|
+
----
|
|
41
|
+
|
|
42
|
+
=== Installing without Bundler
|
|
43
|
+
|
|
44
|
+
Install directly using gem:
|
|
45
|
+
|
|
46
|
+
[source,shell]
|
|
47
|
+
----
|
|
48
|
+
gem install moxml
|
|
49
|
+
gem install nokogiri # Or your preferred adapter
|
|
50
|
+
----
|
|
51
|
+
|
|
52
|
+
=== Adapter selection
|
|
53
|
+
|
|
54
|
+
Moxml automatically detects and uses available XML libraries. The default
|
|
55
|
+
adapter priority order is:
|
|
56
|
+
|
|
57
|
+
. Nokogiri (if available)
|
|
58
|
+
. LibXML (if available)
|
|
59
|
+
. Oga (if available)
|
|
60
|
+
. REXML (always available)
|
|
61
|
+
. Ox (if available)
|
|
62
|
+
|
|
63
|
+
You can override the default adapter in your application:
|
|
64
|
+
|
|
65
|
+
[source,ruby]
|
|
66
|
+
----
|
|
67
|
+
# Set default adapter globally
|
|
68
|
+
Moxml::Config.default_adapter = :libxml
|
|
69
|
+
|
|
70
|
+
# Or configure per instance
|
|
71
|
+
moxml = Moxml.new
|
|
72
|
+
moxml.config.adapter = :oga
|
|
73
|
+
----
|
|
74
|
+
|
|
75
|
+
=== Verifying installation
|
|
76
|
+
|
|
77
|
+
Test your installation:
|
|
78
|
+
|
|
79
|
+
[source,ruby]
|
|
80
|
+
----
|
|
81
|
+
require 'moxml'
|
|
82
|
+
|
|
83
|
+
# Check version
|
|
84
|
+
puts Moxml::VERSION
|
|
85
|
+
|
|
86
|
+
# Verify adapter loaded
|
|
87
|
+
context = Moxml.new
|
|
88
|
+
puts context.config.adapter.name
|
|
89
|
+
# => "Moxml::Adapter::Nokogiri" (or your adapter)
|
|
90
|
+
|
|
91
|
+
# Parse simple XML
|
|
92
|
+
doc = context.parse('<root><child>test</child></root>')
|
|
93
|
+
puts doc.root.name
|
|
94
|
+
# => "root"
|
|
95
|
+
----
|
|
96
|
+
|
|
97
|
+
=== Troubleshooting
|
|
98
|
+
|
|
99
|
+
**Gem not found:**
|
|
100
|
+
|
|
101
|
+
Ensure bundler is using the correct gem source:
|
|
102
|
+
|
|
103
|
+
[source,ruby]
|
|
104
|
+
----
|
|
105
|
+
# Add to top of Gemfile
|
|
106
|
+
source 'https://rubygems.org'
|
|
107
|
+
----
|
|
108
|
+
|
|
109
|
+
**Adapter not loading:**
|
|
110
|
+
|
|
111
|
+
If your chosen adapter isn't loading:
|
|
112
|
+
|
|
113
|
+
. Verify the adapter gem is installed: `bundle list | grep nokogiri`
|
|
114
|
+
. Check for version conflicts: `bundle update moxml`
|
|
115
|
+
. Try explicitly requiring: `require 'nokogiri'` before `require 'moxml'`
|
|
116
|
+
|
|
117
|
+
**C extension compilation errors:**
|
|
118
|
+
|
|
119
|
+
If Nokogiri or LibXML fail to install on your system, consider using pure
|
|
120
|
+
Ruby adapters:
|
|
121
|
+
|
|
122
|
+
[source,ruby]
|
|
123
|
+
----
|
|
124
|
+
gem 'moxml'
|
|
125
|
+
gem 'oga' # Pure Ruby alternative
|
|
126
|
+
----
|
|
127
|
+
|
|
128
|
+
Or use REXML which requires no additional gems:
|
|
129
|
+
|
|
130
|
+
[source,ruby]
|
|
131
|
+
----
|
|
132
|
+
gem 'moxml'
|
|
133
|
+
# REXML is included in Ruby standard library
|
|
134
|
+
----
|
|
135
|
+
|
|
136
|
+
=== Next steps
|
|
137
|
+
|
|
138
|
+
* link:../quick-start[Quick start guide] - Get started with basic usage
|
|
139
|
+
* link:adapters/[Learn about adapters] - Understand adapter differences
|
|
140
|
+
* link:../tutorials/[Tutorials] - Step-by-step learning paths
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Node API reference
|
|
3
|
+
nav_order: 5
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Node API reference
|
|
7
|
+
|
|
8
|
+
== XML objects and their methods
|
|
9
|
+
|
|
10
|
+
Each node type provides methods for traversing the document structure:
|
|
11
|
+
|
|
12
|
+
[source,ruby]
|
|
13
|
+
----
|
|
14
|
+
node.parent # Get parent node
|
|
15
|
+
node.children # Get child nodes
|
|
16
|
+
node.next_sibling # Get next sibling
|
|
17
|
+
node.previous_sibling # Get previous sibling
|
|
18
|
+
|
|
19
|
+
# Convenience accessors
|
|
20
|
+
node.first_child # Get first child
|
|
21
|
+
node.last_child # Get last child
|
|
22
|
+
node.has_children? # Check if node has children
|
|
23
|
+
|
|
24
|
+
# Node manipulation
|
|
25
|
+
node.clone # Deep copy of node
|
|
26
|
+
node.dup # Alias for clone
|
|
27
|
+
|
|
28
|
+
# Query methods
|
|
29
|
+
node.find(xpath) # Alias for at_xpath
|
|
30
|
+
node.find_all(xpath) # Returns array of matching elements
|
|
31
|
+
|
|
32
|
+
# Type checking
|
|
33
|
+
node.element? # Is it an element?
|
|
34
|
+
node.text? # Is it a text node?
|
|
35
|
+
node.cdata? # Is it a CDATA section?
|
|
36
|
+
node.comment? # Is it a comment?
|
|
37
|
+
node.processing_instruction? # Is it a PI?
|
|
38
|
+
node.attribute? # Is it an attribute?
|
|
39
|
+
node.namespace? # Is it a namespace?
|
|
40
|
+
|
|
41
|
+
# Node information
|
|
42
|
+
node.document # Get owning document
|
|
43
|
+
----
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
See also:
|
|
47
|
+
|
|
48
|
+
* link:../guides/working-with-documents[Working with documents guide]
|
|
49
|
+
* link:../guides/advanced-features[Advanced features guide]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Performance considerations
|
|
3
|
+
nav_order: 11
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Performance considerations
|
|
7
|
+
|
|
8
|
+
=== Memory management
|
|
9
|
+
|
|
10
|
+
Moxml maintains a node registry to ensure consistent object mapping:
|
|
11
|
+
|
|
12
|
+
[source,ruby]
|
|
13
|
+
----
|
|
14
|
+
doc = context.parse(large_xml)
|
|
15
|
+
# Process document
|
|
16
|
+
doc = nil # Allow garbage collection of document and registry
|
|
17
|
+
GC.start # Force garbage collection if needed
|
|
18
|
+
----
|
|
19
|
+
|
|
20
|
+
=== Efficient querying
|
|
21
|
+
|
|
22
|
+
Use specific XPath expressions for better performance:
|
|
23
|
+
|
|
24
|
+
[source,ruby]
|
|
25
|
+
----
|
|
26
|
+
# More efficient - specific path
|
|
27
|
+
doc.xpath('//book/title')
|
|
28
|
+
|
|
29
|
+
# Less efficient - requires full document scan
|
|
30
|
+
doc.xpath('//title')
|
|
31
|
+
|
|
32
|
+
# Most efficient - direct child access
|
|
33
|
+
root.xpath('./*/title')
|
|
34
|
+
----
|
|
35
|
+
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quick start
|
|
3
|
+
nav_order: 3
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Quick start
|
|
7
|
+
|
|
8
|
+
=== Purpose
|
|
9
|
+
|
|
10
|
+
Get up and running with Moxml in minutes through practical examples covering
|
|
11
|
+
parsing, creating, querying, and modifying XML documents.
|
|
12
|
+
|
|
13
|
+
=== Prerequisites
|
|
14
|
+
|
|
15
|
+
* Moxml installed with at least one adapter
|
|
16
|
+
* Basic familiarity with XML concepts
|
|
17
|
+
* Ruby 3.0 or higher
|
|
18
|
+
|
|
19
|
+
=== Parse and query XML
|
|
20
|
+
|
|
21
|
+
The most common operation is parsing existing XML and querying it:
|
|
22
|
+
|
|
23
|
+
[source,ruby]
|
|
24
|
+
----
|
|
25
|
+
require 'moxml'
|
|
26
|
+
|
|
27
|
+
xml = <<~XML
|
|
28
|
+
<library>
|
|
29
|
+
<book id="1">
|
|
30
|
+
<title>Ruby Programming</title>
|
|
31
|
+
<author>Jane Smith</author>
|
|
32
|
+
<price>29.99</price>
|
|
33
|
+
</book>
|
|
34
|
+
<book id="2">
|
|
35
|
+
<title>Advanced Ruby</title>
|
|
36
|
+
<author>John Doe</author>
|
|
37
|
+
<price>39.99</price>
|
|
38
|
+
</book>
|
|
39
|
+
</library>
|
|
40
|
+
XML
|
|
41
|
+
|
|
42
|
+
# Parse the XML
|
|
43
|
+
doc = Moxml.new.parse(xml)
|
|
44
|
+
|
|
45
|
+
# Query using XPath
|
|
46
|
+
books = doc.xpath('//book')
|
|
47
|
+
puts "Found #{books.length} books" # => Found 2 books
|
|
48
|
+
|
|
49
|
+
# Access specific book
|
|
50
|
+
first_book = doc.at_xpath('//book[@id="1"]')
|
|
51
|
+
puts first_book['id'] # => "1"
|
|
52
|
+
puts first_book.at_xpath('.//title').text # => "Ruby Programming"
|
|
53
|
+
|
|
54
|
+
# Find all titles
|
|
55
|
+
titles = doc.xpath('//book/title')
|
|
56
|
+
titles.each { |title| puts title.text }
|
|
57
|
+
# => Ruby Programming
|
|
58
|
+
# => Advanced Ruby
|
|
59
|
+
----
|
|
60
|
+
|
|
61
|
+
=== Create XML documents
|
|
62
|
+
|
|
63
|
+
Build XML documents from scratch using the builder pattern:
|
|
64
|
+
|
|
65
|
+
[source,ruby]
|
|
66
|
+
----
|
|
67
|
+
require 'moxml'
|
|
68
|
+
|
|
69
|
+
doc = Moxml::Builder.build(Moxml.new) do |xml|
|
|
70
|
+
xml.declaration version: "1.0", encoding: "UTF-8"
|
|
71
|
+
|
|
72
|
+
xml.library do
|
|
73
|
+
xml.book id: "1" do
|
|
74
|
+
xml.title "Ruby Programming"
|
|
75
|
+
xml.author "Jane Smith"
|
|
76
|
+
xml.price "29.99"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
xml.book id: "2" do
|
|
80
|
+
xml.title "Advanced Ruby"
|
|
81
|
+
xml.author "John Doe"
|
|
82
|
+
xml.price "39.99"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
puts doc.to_xml(indent: 2)
|
|
88
|
+
----
|
|
89
|
+
|
|
90
|
+
Output:
|
|
91
|
+
|
|
92
|
+
[source,xml]
|
|
93
|
+
----
|
|
94
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
95
|
+
<library>
|
|
96
|
+
<book id="1">
|
|
97
|
+
<title>Ruby Programming</title>
|
|
98
|
+
<author>Jane Smith</author>
|
|
99
|
+
<price>29.99</price>
|
|
100
|
+
</book>
|
|
101
|
+
<book id="2">
|
|
102
|
+
<title>Advanced Ruby</title>
|
|
103
|
+
<author>John Doe</author>
|
|
104
|
+
<price>39.99</price>
|
|
105
|
+
</book>
|
|
106
|
+
</library>
|
|
107
|
+
----
|
|
108
|
+
|
|
109
|
+
=== Modify existing XML
|
|
110
|
+
|
|
111
|
+
Add, update, and remove elements and attributes:
|
|
112
|
+
|
|
113
|
+
[source,ruby]
|
|
114
|
+
----
|
|
115
|
+
require 'moxml'
|
|
116
|
+
|
|
117
|
+
# Parse existing XML
|
|
118
|
+
xml = '<library><book id="1"><title>Old Title</title></book></library>'
|
|
119
|
+
doc = Moxml.new.parse(xml)
|
|
120
|
+
|
|
121
|
+
# Find and modify element
|
|
122
|
+
book = doc.at_xpath('//book[@id="1"]')
|
|
123
|
+
|
|
124
|
+
# Update text content
|
|
125
|
+
book.at_xpath('.//title').text = 'New Title'
|
|
126
|
+
|
|
127
|
+
# Update attribute
|
|
128
|
+
book['id'] = '100'
|
|
129
|
+
book['edition'] = '2nd'
|
|
130
|
+
|
|
131
|
+
# Add new child element
|
|
132
|
+
author = doc.create_element('author')
|
|
133
|
+
author.text = 'Jane Smith'
|
|
134
|
+
book.add_child(author)
|
|
135
|
+
|
|
136
|
+
# Add comment
|
|
137
|
+
book.add_child(doc.create_comment('Updated book'))
|
|
138
|
+
|
|
139
|
+
# Remove attribute
|
|
140
|
+
book.remove_attribute('edition')
|
|
141
|
+
|
|
142
|
+
puts doc.to_xml(indent: 2)
|
|
143
|
+
----
|
|
144
|
+
|
|
145
|
+
=== Work with namespaces
|
|
146
|
+
|
|
147
|
+
Handle XML namespaces properly:
|
|
148
|
+
|
|
149
|
+
[source,ruby]
|
|
150
|
+
----
|
|
151
|
+
require 'moxml'
|
|
152
|
+
|
|
153
|
+
xml = <<~XML
|
|
154
|
+
<library xmlns="http://example.org/library"
|
|
155
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
156
|
+
<book>
|
|
157
|
+
<dc:title>Ruby Programming</dc:title>
|
|
158
|
+
<dc:creator>Jane Smith</dc:creator>
|
|
159
|
+
</book>
|
|
160
|
+
</library>
|
|
161
|
+
XML
|
|
162
|
+
|
|
163
|
+
doc = Moxml.new.parse(xml)
|
|
164
|
+
|
|
165
|
+
# Query with namespace mapping
|
|
166
|
+
namespaces = {
|
|
167
|
+
'lib' => 'http://example.org/library',
|
|
168
|
+
'dc' => 'http://purl.org/dc/elements/1.1/'
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
books = doc.xpath('//lib:book', namespaces)
|
|
172
|
+
titles = doc.xpath('//dc:title', namespaces)
|
|
173
|
+
|
|
174
|
+
puts titles.first.text # => "Ruby Programming"
|
|
175
|
+
|
|
176
|
+
# Create namespaced elements
|
|
177
|
+
new_book = doc.create_element('book')
|
|
178
|
+
new_book.add_namespace('dc', 'http://purl.org/dc/elements/1.1/')
|
|
179
|
+
|
|
180
|
+
title = doc.create_element('dc:title')
|
|
181
|
+
title.text = 'Advanced Ruby'
|
|
182
|
+
new_book.add_child(title)
|
|
183
|
+
----
|
|
184
|
+
|
|
185
|
+
=== Switch adapters
|
|
186
|
+
|
|
187
|
+
Choose a different XML adapter based on your needs:
|
|
188
|
+
|
|
189
|
+
[source,ruby]
|
|
190
|
+
----
|
|
191
|
+
require 'moxml'
|
|
192
|
+
|
|
193
|
+
# Use Nokogiri (default)
|
|
194
|
+
context_nokogiri = Moxml.new
|
|
195
|
+
|
|
196
|
+
# Use LibXML for native performance
|
|
197
|
+
context_libxml = Moxml.new
|
|
198
|
+
context_libxml.config.adapter = :libxml
|
|
199
|
+
|
|
200
|
+
# Use Oga for pure Ruby
|
|
201
|
+
context_oga = Moxml.new
|
|
202
|
+
context_oga.config.adapter = :oga
|
|
203
|
+
|
|
204
|
+
# Use REXML for standard library only
|
|
205
|
+
context_rexml = Moxml.new
|
|
206
|
+
context_rexml.config.adapter = :rexml
|
|
207
|
+
|
|
208
|
+
# Parse with chosen adapter
|
|
209
|
+
doc = context_libxml.parse(xml)
|
|
210
|
+
----
|
|
211
|
+
|
|
212
|
+
=== Handle errors
|
|
213
|
+
|
|
214
|
+
Moxml provides comprehensive error handling:
|
|
215
|
+
|
|
216
|
+
[source,ruby]
|
|
217
|
+
----
|
|
218
|
+
require 'moxml'
|
|
219
|
+
|
|
220
|
+
begin
|
|
221
|
+
# Parse malformed XML
|
|
222
|
+
doc = Moxml.new.parse('<invalid><unclosed>', strict: true)
|
|
223
|
+
rescue Moxml::ParseError => e
|
|
224
|
+
puts "Parse error at line #{e.line}: #{e.message}"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
begin
|
|
228
|
+
# Invalid XPath expression
|
|
229
|
+
doc.xpath('//invalid[[[')
|
|
230
|
+
rescue Moxml::XPathError => e
|
|
231
|
+
puts "XPath error: #{e.expression}"
|
|
232
|
+
puts e.to_s # Includes helpful hints
|
|
233
|
+
end
|
|
234
|
+
----
|
|
235
|
+
|
|
236
|
+
=== Next steps
|
|
237
|
+
|
|
238
|
+
Now that you've seen the basics, explore more:
|
|
239
|
+
|
|
240
|
+
* link:../tutorials/[Tutorials] - Learn Moxml step by step
|
|
241
|
+
* link:adapters/[Adapters] - Choose the right adapter for your needs
|
|
242
|
+
* link:../guides/[Guides] - Task-oriented documentation
|
|
243
|
+
* link:../references/[API Reference] - Complete technical documentation
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Thread safety
|
|
3
|
+
nav_order: 10
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
== Thread safety
|
|
7
|
+
|
|
8
|
+
Moxml is thread-safe when used properly. Each instance maintains its own state
|
|
9
|
+
and can be used safely in concurrent operations:
|
|
10
|
+
|
|
11
|
+
[source,ruby]
|
|
12
|
+
----
|
|
13
|
+
class XmlProcessor
|
|
14
|
+
def initialize
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
@context = Moxml.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def process(xml)
|
|
20
|
+
@mutex.synchronize do
|
|
21
|
+
doc = @context.parse(xml)
|
|
22
|
+
# Modify document
|
|
23
|
+
doc.to_xml
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
----
|
|
28
|
+
|