moxml 0.5.136 → 0.5.137
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/customized_leptris.rb +0 -1
- data/lib/moxml/adapter/leptris/document_parts.rb +0 -2
- data/lib/moxml/adapter/leptris/markers.rb +1 -2
- data/lib/moxml/adapter/leptris/serialize.rb +1 -1
- data/lib/moxml/adapter/leptris.rb +3 -25
- data/lib/moxml/attribute_resolver.rb +23 -0
- data/lib/moxml/element.rb +7 -3
- data/lib/moxml/version.rb +1 -1
- data/spec/integration/shared_examples/node_wrappers/attribute_behavior.rb +35 -0
- metadata +2 -3
- data/lib/moxml/adapter/customized_leptris/document_pi.rb +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 43beff2cbabe6c8800099bc8f56a76b4c2510c6158cb632984cd31c8c3893a24
|
|
4
|
+
data.tar.gz: e7d0540ce919c428a26b55805f0c78fc25de976c08f2639a83161eab6ffc3b4d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8e33f465faabc1da5cc0c7233f70e60592e0080cb4897b81d98eb1b073fedeea21160d2252170e322c8a66b33f4899e1752f96b30555ba0959f4b6f2e46ecd8b
|
|
7
|
+
data.tar.gz: 29dde54bd4af8259207a708175309fdf9ad7fd3c4702eacf1e77a92d5fbfbd03b0993d2730c70ddb0c5b30edc41bbc4871e73d10334814fd51b813f2e6905629
|
|
@@ -12,7 +12,6 @@ module Moxml
|
|
|
12
12
|
autoload :Doctype, "moxml/adapter/customized_leptris/doctype"
|
|
13
13
|
autoload :EntityReference, "moxml/adapter/customized_leptris/entity_reference"
|
|
14
14
|
autoload :TextSegment, "moxml/adapter/customized_leptris/text_segment"
|
|
15
|
-
autoload :DocumentPI, "moxml/adapter/customized_leptris/document_pi"
|
|
16
15
|
end
|
|
17
16
|
end
|
|
18
17
|
end
|
|
@@ -83,8 +83,6 @@ module Moxml
|
|
|
83
83
|
doc.root = child
|
|
84
84
|
when ::Leptris::XML::ProcessingInstruction
|
|
85
85
|
doc.add_pi(child.target, child.content.to_s)
|
|
86
|
-
when CustomizedLeptris::DocumentPI
|
|
87
|
-
doc.add_pi(child.target, child.data)
|
|
88
86
|
when ::Leptris::XML::Text
|
|
89
87
|
texts = attachments.get(doc, :document_text) || []
|
|
90
88
|
texts << child
|
|
@@ -20,8 +20,7 @@ module Moxml
|
|
|
20
20
|
|
|
21
21
|
case native
|
|
22
22
|
when CustomizedLeptris::Declaration, CustomizedLeptris::Doctype,
|
|
23
|
-
CustomizedLeptris::EntityReference, CustomizedLeptris::TextSegment
|
|
24
|
-
CustomizedLeptris::DocumentPI
|
|
23
|
+
CustomizedLeptris::EntityReference, CustomizedLeptris::TextSegment
|
|
25
24
|
true
|
|
26
25
|
else
|
|
27
26
|
# Parentless elements come only from Iterparse —
|
|
@@ -86,7 +86,7 @@ module Moxml
|
|
|
86
86
|
# binding, so a Text branch first would swallow CDATA nodes.
|
|
87
87
|
case node
|
|
88
88
|
when CustomizedLeptris::Declaration, CustomizedLeptris::Doctype,
|
|
89
|
-
CustomizedLeptris::EntityReference
|
|
89
|
+
CustomizedLeptris::EntityReference
|
|
90
90
|
return node.to_xml
|
|
91
91
|
when ::Leptris::XML::CDATA
|
|
92
92
|
return XmlEmitter.cdata(node.content)
|
|
@@ -1639,7 +1639,7 @@ module Moxml
|
|
|
1639
1639
|
when ::Leptris::XML::Text, CustomizedLeptris::TextSegment then :text
|
|
1640
1640
|
when ::Leptris::XML::Attr, ::Leptris::XML::ResultAttr then :attribute
|
|
1641
1641
|
when ::Leptris::XML::Comment then :comment
|
|
1642
|
-
when ::Leptris::XML::ProcessingInstruction
|
|
1642
|
+
when ::Leptris::XML::ProcessingInstruction then :processing_instruction
|
|
1643
1643
|
when ::Leptris::XML::Document then :document
|
|
1644
1644
|
when ::Leptris::XML::DocType, CustomizedLeptris::Doctype then :doctype
|
|
1645
1645
|
when CustomizedLeptris::Declaration then :declaration
|
|
@@ -1666,7 +1666,6 @@ module Moxml
|
|
|
1666
1666
|
|
|
1667
1667
|
def node_name(node)
|
|
1668
1668
|
return node.root_name if node.is_a?(::Leptris::XML::DocType)
|
|
1669
|
-
return node.target if node.is_a?(CustomizedLeptris::DocumentPI)
|
|
1670
1669
|
|
|
1671
1670
|
if NATIVE_READ_LAYER && node.is_a?(::Leptris::XML::NativeNode)
|
|
1672
1671
|
# PIs expose no name through the native layer.
|
|
@@ -1684,7 +1683,7 @@ module Moxml
|
|
|
1684
1683
|
def set_node_name(node, name)
|
|
1685
1684
|
node = to_binding(node) if NATIVE_READ_LAYER
|
|
1686
1685
|
case node
|
|
1687
|
-
when ::Leptris::XML::ProcessingInstruction
|
|
1686
|
+
when ::Leptris::XML::ProcessingInstruction then node.target = name
|
|
1688
1687
|
else node.name = name
|
|
1689
1688
|
end
|
|
1690
1689
|
end
|
|
@@ -1698,8 +1697,6 @@ module Moxml
|
|
|
1698
1697
|
CustomizedLeptris::Doctype.new(node.name, node.external_id, node.system_id)
|
|
1699
1698
|
when CustomizedLeptris::EntityReference
|
|
1700
1699
|
CustomizedLeptris::EntityReference.new(node.name)
|
|
1701
|
-
when CustomizedLeptris::DocumentPI
|
|
1702
|
-
CustomizedLeptris::DocumentPI.new(node.target, node.data, node.parent_doc)
|
|
1703
1700
|
else
|
|
1704
1701
|
node.dup
|
|
1705
1702
|
end
|
|
@@ -1796,7 +1793,6 @@ module Moxml
|
|
|
1796
1793
|
assemble_document_children(node)
|
|
1797
1794
|
when CustomizedLeptris::Declaration, CustomizedLeptris::Doctype,
|
|
1798
1795
|
CustomizedLeptris::EntityReference, CustomizedLeptris::TextSegment,
|
|
1799
|
-
CustomizedLeptris::DocumentPI,
|
|
1800
1796
|
# Terminal node kinds pay an FFI round trip for an empty
|
|
1801
1797
|
# list; unfiltered recursions visit every text node.
|
|
1802
1798
|
::Leptris::XML::Text, ::Leptris::XML::Comment,
|
|
@@ -1832,8 +1828,7 @@ module Moxml
|
|
|
1832
1828
|
case node
|
|
1833
1829
|
when ::Leptris::XML::Element then root_parent(node)
|
|
1834
1830
|
when ::Leptris::XML::Document then nil
|
|
1835
|
-
when CustomizedLeptris::Declaration, CustomizedLeptris::Doctype
|
|
1836
|
-
CustomizedLeptris::DocumentPI then node.parent_doc
|
|
1831
|
+
when CustomizedLeptris::Declaration, CustomizedLeptris::Doctype then node.parent_doc
|
|
1837
1832
|
when CustomizedLeptris::TextSegment, CustomizedLeptris::EntityReference then node.parent
|
|
1838
1833
|
# Same body as the Element arm by design (frequency
|
|
1839
1834
|
# ordering); the generic kinds are cold.
|
|
@@ -2535,23 +2530,6 @@ module Moxml
|
|
|
2535
2530
|
end
|
|
2536
2531
|
when CustomizedLeptris::EntityReference
|
|
2537
2532
|
marker_text_for(node.parent, node.name)&.unlink
|
|
2538
|
-
when CustomizedLeptris::DocumentPI
|
|
2539
|
-
if NATIVE_DOC_PARTS && node.parent_doc
|
|
2540
|
-
pis = node.parent_doc.processing_instructions
|
|
2541
|
-
index = pis.index do |target, data|
|
|
2542
|
-
target == node.target && data == node.data
|
|
2543
|
-
end
|
|
2544
|
-
if index
|
|
2545
|
-
node.parent_doc.remove_pi(index)
|
|
2546
|
-
node.parent_doc = nil
|
|
2547
|
-
end
|
|
2548
|
-
else
|
|
2549
|
-
raise Moxml::NotImplementedError.new(
|
|
2550
|
-
"libleptris has no document-level PI removal",
|
|
2551
|
-
adapter: :leptris,
|
|
2552
|
-
feature: :remove,
|
|
2553
|
-
)
|
|
2554
|
-
end
|
|
2555
2533
|
else
|
|
2556
2534
|
begin
|
|
2557
2535
|
node.unlink
|
|
@@ -142,6 +142,16 @@ module Moxml
|
|
|
142
142
|
# Remove the attribute named by XML-correct resolution (see
|
|
143
143
|
# #assign for the name semantics).
|
|
144
144
|
#
|
|
145
|
+
# #378: a bare name that matches no no-namespace attribute falls
|
|
146
|
+
# back to the SINGLE namespaced attribute carrying that local
|
|
147
|
+
# name — callers spelling the local part (the name
|
|
148
|
+
# attribute_nodes-style listings expose) expect removal, and the
|
|
149
|
+
# silent no-op broke remediation flows. Bare-name resolution
|
|
150
|
+
# keeps Namespaces 1.0 §5.2 semantics for reads; removal widens
|
|
151
|
+
# only when unambiguous. Several prefixed spellings sharing the
|
|
152
|
+
# local name remove nothing — guessing a prefix would corrupt
|
|
153
|
+
# documents.
|
|
154
|
+
#
|
|
145
155
|
# @return [Moxml::Attribute, nil] the removed attribute
|
|
146
156
|
def remove(element, name)
|
|
147
157
|
name = name.to_s
|
|
@@ -153,6 +163,8 @@ module Moxml
|
|
|
153
163
|
end
|
|
154
164
|
|
|
155
165
|
attr = resolve(element, name)
|
|
166
|
+
attr ||= resolve_unique_local(element, name) unless name.include?(":")
|
|
167
|
+
|
|
156
168
|
return nil unless attr
|
|
157
169
|
|
|
158
170
|
adapter.remove_attribute_native(attr.native)
|
|
@@ -160,6 +172,17 @@ module Moxml
|
|
|
160
172
|
attr
|
|
161
173
|
end
|
|
162
174
|
|
|
175
|
+
# The single namespaced attribute whose local name matches, or
|
|
176
|
+
# nil when none or several do (see #remove).
|
|
177
|
+
def resolve_unique_local(element, local)
|
|
178
|
+
matches = element.attributes.select do |attr|
|
|
179
|
+
attr_name = attr.name
|
|
180
|
+
local_name(attr_name) == local &&
|
|
181
|
+
!attribute_uri(element, attr, attr_name).nil?
|
|
182
|
+
end
|
|
183
|
+
matches.one? ? matches.first : nil
|
|
184
|
+
end
|
|
185
|
+
|
|
163
186
|
# XPath 1.0 attribute node test, sharing the resolver's
|
|
164
187
|
# expanded-name semantics:
|
|
165
188
|
#
|
data/lib/moxml/element.rb
CHANGED
|
@@ -233,11 +233,15 @@ module Moxml
|
|
|
233
233
|
adapter.attachments.set(@native, :children_source_docs, merged)
|
|
234
234
|
end
|
|
235
235
|
|
|
236
|
+
# Removes the attribute named by XML-correct resolution — a
|
|
237
|
+
# qualified name ("p:x"), or a bare name (the no-namespace
|
|
238
|
+
# attribute, falling back to the single namespaced attribute
|
|
239
|
+
# carrying that local name when no bare one exists, #378).
|
|
240
|
+
#
|
|
241
|
+
# @return [Moxml::Attribute, nil] the removed attribute, nil
|
|
242
|
+
# when nothing matched (nokogiri-compatible)
|
|
236
243
|
def remove_attribute(name)
|
|
237
|
-
# Both remove paths end in invalidate_attribute_cache!, which
|
|
238
|
-
# bumps the generation.
|
|
239
244
|
Moxml::AttributeResolver.remove(self, name)
|
|
240
|
-
self
|
|
241
245
|
end
|
|
242
246
|
|
|
243
247
|
# Append a raw XML fragment's top-level nodes as children.
|
data/lib/moxml/version.rb
CHANGED
|
@@ -126,6 +126,41 @@ RSpec.shared_examples "Moxml::Attribute" do
|
|
|
126
126
|
end
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
+
describe "removing by local name (#378)" do
|
|
130
|
+
before do
|
|
131
|
+
element.add_namespace("q", "http://x.org")
|
|
132
|
+
element["q:type"] = "namespaced"
|
|
133
|
+
element["type"] = "bare"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "removes the single namespaced attribute carrying that local name" do
|
|
137
|
+
element.remove_attribute("type")
|
|
138
|
+
element.remove_attribute("type")
|
|
139
|
+
|
|
140
|
+
expect(element["q:type"]).to be_nil
|
|
141
|
+
expect(element["type"]).to be_nil
|
|
142
|
+
expect(element.attributes).to be_empty
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "returns the removed attribute, nil when nothing matched" do
|
|
146
|
+
removed = element.remove_attribute("type")
|
|
147
|
+
|
|
148
|
+
expect(removed).to be_a(described_class)
|
|
149
|
+
expect(element["type"]).to be_nil
|
|
150
|
+
expect(element.remove_attribute("nonexistent")).to be_nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "removes nothing when several prefixes share the local name" do
|
|
154
|
+
element.remove_attribute("type")
|
|
155
|
+
element.add_namespace("other", "http://other.org")
|
|
156
|
+
element["other:type"] = "second"
|
|
157
|
+
|
|
158
|
+
expect(element.remove_attribute("type")).to be_nil
|
|
159
|
+
expect(element["q:type"]).to eq("namespaced")
|
|
160
|
+
expect(element["other:type"]).to eq("second")
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
129
164
|
describe "manipulation" do
|
|
130
165
|
before do
|
|
131
166
|
element["test"] = "value"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
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.137
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |
|
|
14
14
|
Moxml is a unified XML manipulation library that provides a common API
|
|
@@ -134,7 +134,6 @@ files:
|
|
|
134
134
|
- lib/moxml/adapter/customized_leptris.rb
|
|
135
135
|
- lib/moxml/adapter/customized_leptris/declaration.rb
|
|
136
136
|
- lib/moxml/adapter/customized_leptris/doctype.rb
|
|
137
|
-
- lib/moxml/adapter/customized_leptris/document_pi.rb
|
|
138
137
|
- lib/moxml/adapter/customized_leptris/entity_reference.rb
|
|
139
138
|
- lib/moxml/adapter/customized_leptris/text_segment.rb
|
|
140
139
|
- lib/moxml/adapter/customized_libxml.rb
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Moxml
|
|
4
|
-
module Adapter
|
|
5
|
-
module CustomizedLeptris
|
|
6
|
-
# Document-level processing instruction. libleptris stores these
|
|
7
|
-
# outside the element tree (a flat, document-ordered list with no
|
|
8
|
-
# prolog/epilog anchoring — its serializer emits them all before
|
|
9
|
-
# the root), reachable through Document#processing_instructions
|
|
10
|
-
# as [target, data] pairs. This pseudo-native gives the pairs a
|
|
11
|
-
# node identity so the moxml contract can list them as document
|
|
12
|
-
# children (and answer mutations: creation routes native via
|
|
13
|
-
# add_pi; removal has no engine entry).
|
|
14
|
-
class DocumentPI
|
|
15
|
-
attr_accessor :target, :data, :parent_doc
|
|
16
|
-
alias content data
|
|
17
|
-
alias content= data=
|
|
18
|
-
|
|
19
|
-
def initialize(target, data = "", parent_doc = nil)
|
|
20
|
-
@target = target
|
|
21
|
-
@data = data.to_s
|
|
22
|
-
@parent_doc = parent_doc
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def to_xml
|
|
26
|
-
data.empty? ? "<?#{target}?>" : "<?#{target} #{data}?>"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def ==(other)
|
|
30
|
-
other.is_a?(self.class) && target == other.target && data == other.data
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|