moxml 0.5.137 → 0.5.138
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/lib/moxml/adapter/leptris/document_parts.rb +14 -1
- data/lib/moxml/adapter/libxml.rb +13 -0
- data/lib/moxml/adapter/nokogiri.rb +5 -1
- data/lib/moxml/adapter/rexml.rb +5 -2
- data/lib/moxml/version.rb +1 -1
- data/spec/consistency/xpath_idioms_spec.rb +62 -0
- data/spec/moxml/adapter/leptris_document_declaration_spec.rb +42 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20467d4026cf631dd85798aaaa47a53526e1a6c8e26b1583ac896e56bb0fa4b4
|
|
4
|
+
data.tar.gz: 3d3829939332dfd24a1d552308d10fd7c0dbbe6eed998a5292ec5a5d82d53def
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 353a615d10c7755a3d03a5dd13988eb57b1f30b2bc68f1506e68bc48d053deca42fd968cbba67f5df10cd14dff7da757bfd15f89a734cd1e607e34d3b319eb0a
|
|
7
|
+
data.tar.gz: bfa917028338657c3c09d91f32a964a653f4e50bc8d5abd1d0c7cf404d284d2efb216b0e62df1f17f1d731ef636c6d60bbe27a5f587ccca2c45bb65aa93c8e39
|
|
@@ -36,7 +36,13 @@ module Moxml
|
|
|
36
36
|
# Nokogiri-shaped contract, epilog anchoring included (issue
|
|
37
37
|
# #130). Built documents reflect their parts immediately
|
|
38
38
|
# since leptris-ruby 1.9.32 (leptris-ruby#91).
|
|
39
|
-
|
|
39
|
+
# leptris-ruby#459 lists the declaration among the binding
|
|
40
|
+
# children; the Nokogiri-shaped facade contract never lists
|
|
41
|
+
# it (the declaration is a preamble part, not a child node)
|
|
42
|
+
# — filtered at the listing seam.
|
|
43
|
+
children.concat(
|
|
44
|
+
doc.children.to_a.grep_v(::Leptris::XML::Declaration),
|
|
45
|
+
)
|
|
40
46
|
|
|
41
47
|
texts = attachments.get(doc, :document_text)
|
|
42
48
|
children.concat(texts) if texts
|
|
@@ -156,6 +162,13 @@ module Moxml
|
|
|
156
162
|
next
|
|
157
163
|
end
|
|
158
164
|
|
|
165
|
+
# leptris-ruby#459 exposes the declaration as a
|
|
166
|
+
# Document#children entry; the preamble above owns the
|
|
167
|
+
# emission (a second line here duplicates it — and the
|
|
168
|
+
# 1.9.360 0-arity Declaration#to_xml raises under the
|
|
169
|
+
# options-passing call).
|
|
170
|
+
next if child.is_a?(::Leptris::XML::Declaration)
|
|
171
|
+
|
|
159
172
|
parts << raw_serialize(child, options) << "\n"
|
|
160
173
|
end
|
|
161
174
|
|
data/lib/moxml/adapter/libxml.rb
CHANGED
|
@@ -244,6 +244,9 @@ module Moxml
|
|
|
244
244
|
return NATIVE_NODE_TYPE_MAP[node.node_type] || :unknown
|
|
245
245
|
end
|
|
246
246
|
return :document if node.is_a?(::LibXML::XML::Document)
|
|
247
|
+
# Attr is a separate class (not ::Node) — attribute-terminal
|
|
248
|
+
# XPath results mint as plain Node without this.
|
|
249
|
+
return :attribute if node.is_a?(::LibXML::XML::Attr)
|
|
247
250
|
|
|
248
251
|
wrapper_type = WRAPPER_NODE_TYPE_MAP[node.class]
|
|
249
252
|
return wrapper_type if wrapper_type
|
|
@@ -949,6 +952,16 @@ module Moxml
|
|
|
949
952
|
native_node = unpatch_node(node)
|
|
950
953
|
return [] unless native_node
|
|
951
954
|
|
|
955
|
+
# libxml-ruby's Document#find returns EMPTY for relative
|
|
956
|
+
# paths (nokogiri/libxml2 evaluate them fine): a relative
|
|
957
|
+
# expression from the document node is equivalent to the
|
|
958
|
+
# absolute form — the document's only name-testable child
|
|
959
|
+
# is the root — so rewrite instead of losing the match.
|
|
960
|
+
if native_node.is_a?(::LibXML::XML::Document) &&
|
|
961
|
+
expression.match?(/\A[A-Za-z_*@]/)
|
|
962
|
+
expression = "/#{expression}"
|
|
963
|
+
end
|
|
964
|
+
|
|
952
965
|
# Build namespace context for LibXML
|
|
953
966
|
# LibXML requires ALL prefixes in the XPath to be registered
|
|
954
967
|
ns_context = build_xpath_namespaces(native_node, namespaces)
|
|
@@ -626,7 +626,11 @@ module Moxml
|
|
|
626
626
|
end
|
|
627
627
|
|
|
628
628
|
def xpath(node, expression, namespaces = nil)
|
|
629
|
-
|
|
629
|
+
# An explicit bindings hash — even EMPTY — makes nokogiri
|
|
630
|
+
# register a prefix context, which disables libxml2's
|
|
631
|
+
# literal xmlns: default-namespace handling. Only pass the
|
|
632
|
+
# hash when the caller actually bound something.
|
|
633
|
+
result = namespaces.nil? || namespaces.empty? ? node.xpath(expression) : node.xpath(expression, namespaces)
|
|
630
634
|
# Adapter contract: Array<native> | LazyNodeSet | scalar
|
|
631
635
|
# (count(), string-length(), boolean functions return
|
|
632
636
|
# scalars). The native node-set passes through lazily —
|
data/lib/moxml/adapter/rexml.rb
CHANGED
|
@@ -604,10 +604,13 @@ module Moxml
|
|
|
604
604
|
end
|
|
605
605
|
|
|
606
606
|
def xpath(node, expression, namespaces = {})
|
|
607
|
+
# XPath.match for every expression: get_elements only
|
|
608
|
+
# handles simple child-name paths — attribute terminals,
|
|
609
|
+
# absolute paths and predicates silently degrade there.
|
|
607
610
|
if namespaces && !namespaces.empty?
|
|
608
|
-
::REXML::XPath.match(node, expression, namespaces)
|
|
611
|
+
::REXML::XPath.match(node, expression, namespaces).to_a
|
|
609
612
|
else
|
|
610
|
-
|
|
613
|
+
::REXML::XPath.match(node, expression).to_a
|
|
611
614
|
end
|
|
612
615
|
rescue ::REXML::ParseException => e
|
|
613
616
|
raise Moxml::XPathError.new(
|
data/lib/moxml/version.rb
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# Cross-adapter XPath idioms that nokogiri consumers rely on:
|
|
6
|
+
#
|
|
7
|
+
# - The literal xmlns: prefix resolves against the default namespace
|
|
8
|
+
# (the libxml2 quirk that is nokogiri's documented way to match
|
|
9
|
+
# default-namespaced elements; leptris carries it since engine
|
|
10
|
+
# 1.9.359 / leptris-ruby#469; moxml's own engine always has).
|
|
11
|
+
# - Attribute-terminal steps work in every path position
|
|
12
|
+
# (leptris-ruby#458's table: //a/@id, //@id, r/a/@id,
|
|
13
|
+
# //*[f()]/@id — fixed by the engine's VM path work).
|
|
14
|
+
RSpec.describe "XPath idioms across adapters" do
|
|
15
|
+
let(:default_ns_xml) do
|
|
16
|
+
'<svgmap xmlns="http://www.example.org/doc"><target href="a"/></svgmap>'
|
|
17
|
+
end
|
|
18
|
+
let(:plain_xml) { '<r><a id="x"><b/></a></r>' }
|
|
19
|
+
|
|
20
|
+
Moxml::Adapter::AVAILABLE_ADAPTERS.each do |adapter_name|
|
|
21
|
+
next if adapter_name == :headed_ox # same engine as :ox
|
|
22
|
+
|
|
23
|
+
context "with #{adapter_name}" do
|
|
24
|
+
let(:ctx) { Moxml.new(adapter_name) }
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
if adapter_name == :leptris &&
|
|
28
|
+
Gem::Version.new(Leptris::VERSION) < Gem::Version.new("1.9.359.0")
|
|
29
|
+
skip "binding #{Leptris::VERSION} predates the xmlns: fix (1.9.359)"
|
|
30
|
+
end
|
|
31
|
+
if adapter_name == :oga
|
|
32
|
+
# oga's own Ruby XPath engine has no xmlns: default-ns
|
|
33
|
+
# support (third-party; explicit bindings work).
|
|
34
|
+
skip "oga's XPath engine does not implement the xmlns: idiom"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "matches default-namespaced elements via the xmlns: prefix" do
|
|
39
|
+
doc = ctx.parse(default_ns_xml)
|
|
40
|
+
targets = doc.root.xpath("./xmlns:target")
|
|
41
|
+
expect(targets.length).to eq(1)
|
|
42
|
+
expect(targets.first.name).to eq("target")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "keeps explicit namespace bindings winning over the idiom" do
|
|
46
|
+
doc = ctx.parse(default_ns_xml)
|
|
47
|
+
targets = doc.root.xpath("./xmlns:target", "xmlns" => "urn:bogus")
|
|
48
|
+
expect(targets).to be_empty
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "resolves attribute-terminal steps in every path position" do
|
|
52
|
+
doc = ctx.parse(plain_xml)
|
|
53
|
+
expect(doc.xpath("//a/@id").first&.value).to eq("x")
|
|
54
|
+
expect(doc.xpath("//@id").first&.value).to eq("x")
|
|
55
|
+
expect(doc.xpath("r/a/@id").first&.value).to eq("x")
|
|
56
|
+
expect(
|
|
57
|
+
doc.xpath("//*[local-name()='a']/@id").first&.value,
|
|
58
|
+
).to eq("x")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# leptris-ruby#459 exposes the declaration as a Document#children
|
|
6
|
+
# entry (binding 1.9.360). The serialize child walk must skip it —
|
|
7
|
+
# the composed preamble owns the emission — or declaration-bearing
|
|
8
|
+
# round trips duplicate the line (1.9.359) or raise (1.9.360's
|
|
9
|
+
# 0-arity Declaration#to_xml under the options-passing call).
|
|
10
|
+
RSpec.describe "leptris document declaration child" do
|
|
11
|
+
let(:ctx) { Moxml.new(:leptris) }
|
|
12
|
+
let(:xml) { %(<?xml version="1.0" encoding="UTF-8"?>\n<documents></documents>) }
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
unless Gem::Version.new(Leptris::VERSION) >= Gem::Version.new("1.9.360.0")
|
|
16
|
+
skip "binding #{Leptris::VERSION} predates the declaration child (1.9.360)"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "round trips byte-identical with exactly one declaration" do
|
|
21
|
+
doc = ctx.parse(xml)
|
|
22
|
+
out = doc.to_xml
|
|
23
|
+
|
|
24
|
+
expect(out).to eq("#{xml}\n")
|
|
25
|
+
expect(out.scan("<?xml").length).to eq(1)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "never lists the declaration among document children" do
|
|
29
|
+
doc = ctx.parse(xml)
|
|
30
|
+
first = doc.children.to_a
|
|
31
|
+
second = doc.children.to_a
|
|
32
|
+
|
|
33
|
+
expect(first.map(&:node_type)).to eq(%i[element])
|
|
34
|
+
expect(second.map(&:node_type)).to eq(first.map(&:node_type))
|
|
35
|
+
expect(doc.to_xml).to eq("#{xml}\n")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "keeps declaration-less documents unchanged" do
|
|
39
|
+
doc = ctx.parse("<r/>")
|
|
40
|
+
expect(doc.to_xml).to eq("<r></r>\n")
|
|
41
|
+
end
|
|
42
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: moxml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.138
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -313,6 +313,7 @@ files:
|
|
|
313
313
|
- spec/consistency/eol_normalization_spec.rb
|
|
314
314
|
- spec/consistency/html_doctype_spec.rb
|
|
315
315
|
- spec/consistency/round_trip_spec.rb
|
|
316
|
+
- spec/consistency/xpath_idioms_spec.rb
|
|
316
317
|
- spec/consistency/xslt_spec.rb
|
|
317
318
|
- spec/examples/README.md
|
|
318
319
|
- spec/examples/attribute_examples_spec.rb
|
|
@@ -452,6 +453,7 @@ files:
|
|
|
452
453
|
- spec/moxml/adapter/leptris_attribute_snapshot_spec.rb
|
|
453
454
|
- spec/moxml/adapter/leptris_binding_cap_spec.rb
|
|
454
455
|
- spec/moxml/adapter/leptris_doc_parts_spec.rb
|
|
456
|
+
- spec/moxml/adapter/leptris_document_declaration_spec.rb
|
|
455
457
|
- spec/moxml/adapter/leptris_parse_skips_spec.rb
|
|
456
458
|
- spec/moxml/adapter/leptris_record_driver_spec.rb
|
|
457
459
|
- spec/moxml/adapter/leptris_sax_dup_attr_spec.rb
|