moxml 0.5.51 → 0.5.52
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/base.rb +2 -2
- data/lib/moxml/adapter/leptris.rb +44 -4
- data/lib/moxml/adapter/libxml.rb +1 -1
- data/lib/moxml/adapter/nokogiri.rb +1 -1
- data/lib/moxml/adapter/oga.rb +15 -1
- data/lib/moxml/adapter/ox.rb +1 -1
- data/lib/moxml/adapter/rexml.rb +1 -1
- data/lib/moxml/config.rb +19 -0
- data/lib/moxml/document.rb +2 -1
- data/lib/moxml/version.rb +1 -1
- data/spec/moxml/adapter/leptris_spec.rb +39 -7
- data/spec/moxml/adapter/shared_examples/adapter_contract.rb +2 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5b9e4f8b355a983117cbc435343e414c731791232b8ecee131f5de68fe8e7ce8
|
|
4
|
+
data.tar.gz: 9409d7e0b355d76423acb9abbc812a09665110c53ba29e04cf838d486d257c4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '028a06c0b8f3e041f4ac257df4104052137f4d64d590d1be2c58f093dbf6909685767924c08914e1624daeb7bb8d419e2ad034ae61003a5099e7c673c7ced58b'
|
|
7
|
+
data.tar.gz: 0f737e2a0055194c05492bfebee65253e5a45fffecdd610e0c1f46b53728e23483acc44cdd48165313c213b8fca597685e1bf8e0f28db6afa8a67c28ae1c4167
|
data/lib/moxml/adapter/base.rb
CHANGED
|
@@ -213,9 +213,9 @@ namespace_validation_mode: :strict)
|
|
|
213
213
|
create_native_namespace(element, prefix, uri)
|
|
214
214
|
end
|
|
215
215
|
|
|
216
|
-
def create_entity_reference(name)
|
|
216
|
+
def create_entity_reference(name, owner_doc = nil)
|
|
217
217
|
validate_entity_reference_name(name)
|
|
218
|
-
create_native_entity_reference(name)
|
|
218
|
+
create_native_entity_reference(name, owner_doc)
|
|
219
219
|
end
|
|
220
220
|
|
|
221
221
|
# Mutation return contract: protocol methods that may change
|
|
@@ -103,6 +103,14 @@ module Moxml
|
|
|
103
103
|
NN_ADD_CHILD = NN.instance_method(:add_child)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
+
# Entity-reference preservation (leptris-ruby#212 / upstream
|
|
107
|
+
# #1094): 1.9.177 ships ParseOptions.keep_entity_refs plus
|
|
108
|
+
# first-class EntityReference nodes — the marker machinery
|
|
109
|
+
# becomes bypassable when the Context's entity_mode is :keep.
|
|
110
|
+
NATIVE_ENTITY_REFS =
|
|
111
|
+
defined?(::Leptris::XML::EntityReference) &&
|
|
112
|
+
Gem::Version.new(::Leptris::VERSION) >= Gem::Version.new("1.9.177")
|
|
113
|
+
|
|
106
114
|
# 1.9.163.2 moved the native bulk children into C
|
|
107
115
|
# (Native.bulk_children) and fixed the 512 truncation
|
|
108
116
|
# (leptris-ruby#202). The 162.6-163.1 window carries the
|
|
@@ -493,7 +501,15 @@ module Moxml
|
|
|
493
501
|
xml_string = xml.is_a?(IO) || xml.is_a?(StringIO) ? xml.read : xml.to_s
|
|
494
502
|
# The marker flag rides preprocess's own `&` scan — no
|
|
495
503
|
# second full-buffer probe (issue #132 parse-side note).
|
|
496
|
-
|
|
504
|
+
entity_mode_keep =
|
|
505
|
+
NATIVE_ENTITY_REFS &&
|
|
506
|
+
(_context&.config&.entity_mode == :keep || options[:keep_entity_refs] == true)
|
|
507
|
+
processed, entity_markers =
|
|
508
|
+
if entity_mode_keep
|
|
509
|
+
[xml_string, false]
|
|
510
|
+
else
|
|
511
|
+
Entity.preprocess_with_marker_flag(xml_string)
|
|
512
|
+
end
|
|
497
513
|
|
|
498
514
|
# readonly: true (issue #133): the binding memoizes reads and
|
|
499
515
|
# refuses mutations — the parse-and-read lifecycle for
|
|
@@ -504,7 +520,7 @@ module Moxml
|
|
|
504
520
|
::Leptris::XML::Document.parse(
|
|
505
521
|
processed,
|
|
506
522
|
readonly: options[:readonly] == true,
|
|
507
|
-
options: parse_flags(options),
|
|
523
|
+
options: parse_flags(options, context: _context),
|
|
508
524
|
)
|
|
509
525
|
rescue ::Leptris::XML::ParseError => e
|
|
510
526
|
# libleptris has no recovery mode that survives unclosed
|
|
@@ -534,6 +550,7 @@ module Moxml
|
|
|
534
550
|
|
|
535
551
|
record_source_declaration(native_doc, processed)
|
|
536
552
|
attachments.set(native_doc, :entity_markers, entity_markers)
|
|
553
|
+
attachments.set(native_doc, :keep_entity_refs, entity_mode_keep)
|
|
537
554
|
bump_serialize_generation
|
|
538
555
|
attachments.set(native_doc, :parse_errors, recover_errors) if recover_errors
|
|
539
556
|
|
|
@@ -601,9 +618,12 @@ module Moxml
|
|
|
601
618
|
# Nokogiri semantics: blanks kept, no ATTLIST defaults).
|
|
602
619
|
# noblanks forwards only once the engine flag is libxml2-safe
|
|
603
620
|
# (see ENGINE_NOBLANKS_SAFE); otherwise it is moxml-side.
|
|
604
|
-
def parse_flags(options)
|
|
621
|
+
def parse_flags(options, context: nil)
|
|
605
622
|
flags = 0
|
|
606
623
|
flags |= ::Leptris::XML::ParseOptions::DTDATTR if options[:dtdattr] == true
|
|
624
|
+
flags |= ::Leptris::XML::ParseOptions::KEEP_ENTITY_REFS if NATIVE_ENTITY_REFS &&
|
|
625
|
+
(context&.config&.entity_mode == :keep ||
|
|
626
|
+
options[:keep_entity_refs] == true)
|
|
607
627
|
flags |= ::Leptris::XML::ParseOptions::NOBLANKS if options[:noblanks] == true && ENGINE_NOBLANKS_SAFE
|
|
608
628
|
flags.zero? ? nil : ::Leptris::XML::ParseOptions.new(flags)
|
|
609
629
|
end
|
|
@@ -698,11 +718,18 @@ module Moxml
|
|
|
698
718
|
CustomizedLeptris::Declaration.new(version, encoding, standalone)
|
|
699
719
|
end
|
|
700
720
|
|
|
701
|
-
def create_native_entity_reference(name)
|
|
721
|
+
def create_native_entity_reference(name, owner_doc = nil)
|
|
722
|
+
if NATIVE_ENTITY_REFS && owner_doc
|
|
723
|
+
return owner_doc.create_entity_reference(name.to_s)
|
|
724
|
+
end
|
|
725
|
+
|
|
702
726
|
CustomizedLeptris::EntityReference.new(name)
|
|
703
727
|
end
|
|
704
728
|
|
|
705
729
|
def entity_reference_name(node)
|
|
730
|
+
return node.name if NATIVE_ENTITY_REFS &&
|
|
731
|
+
node.is_a?(::Leptris::XML::EntityReference)
|
|
732
|
+
|
|
706
733
|
node.name if node.is_a?(CustomizedLeptris::EntityReference)
|
|
707
734
|
end
|
|
708
735
|
|
|
@@ -884,6 +911,7 @@ module Moxml
|
|
|
884
911
|
when ::Leptris::XML::DocType, CustomizedLeptris::Doctype then :doctype
|
|
885
912
|
when CustomizedLeptris::Declaration then :declaration
|
|
886
913
|
when CustomizedLeptris::EntityReference then :entity_reference
|
|
914
|
+
when ::Leptris::XML::EntityReference then :entity_reference if NATIVE_ENTITY_REFS
|
|
887
915
|
else :unknown
|
|
888
916
|
end
|
|
889
917
|
end
|
|
@@ -945,6 +973,11 @@ module Moxml
|
|
|
945
973
|
end
|
|
946
974
|
|
|
947
975
|
def children(node, entity_bearing: false)
|
|
976
|
+
if NATIVE_ENTITY_REFS &&
|
|
977
|
+
native_keep_entity_refs?(node)
|
|
978
|
+
return to_binding(node).children.to_a
|
|
979
|
+
end
|
|
980
|
+
|
|
948
981
|
if NATIVE_READ_LAYER && node.is_a?(::Leptris::XML::NativeNode)
|
|
949
982
|
# Bulk C children through moxml's own scratch (see
|
|
950
983
|
# NATIVE_READ_LAYER note above). Entity-marker documents
|
|
@@ -1007,6 +1040,13 @@ module Moxml
|
|
|
1007
1040
|
end
|
|
1008
1041
|
end
|
|
1009
1042
|
|
|
1043
|
+
def native_keep_entity_refs?(node)
|
|
1044
|
+
return false unless node.is_a?(::Leptris::XML::NativeNode)
|
|
1045
|
+
|
|
1046
|
+
doc = NN_DOCUMENT.bind_call(node)
|
|
1047
|
+
attachments.get(doc, :keep_entity_refs) == true
|
|
1048
|
+
end
|
|
1049
|
+
|
|
1010
1050
|
def parent(node)
|
|
1011
1051
|
if NATIVE_READ_LAYER && node.is_a?(::Leptris::XML::NativeNode)
|
|
1012
1052
|
parent = NN_PARENT.bind_call(node)
|
data/lib/moxml/adapter/libxml.rb
CHANGED
data/lib/moxml/adapter/oga.rb
CHANGED
|
@@ -103,7 +103,7 @@ module Moxml
|
|
|
103
103
|
text
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
def create_native_entity_reference(name)
|
|
106
|
+
def create_native_entity_reference(name, _owner_doc = nil)
|
|
107
107
|
text = ::Oga::XML::Text.new
|
|
108
108
|
text.text = "#{Entity::MARKER}#{name};"
|
|
109
109
|
attachments.set(text, :entity_name, name)
|
|
@@ -561,6 +561,20 @@ module Moxml
|
|
|
561
561
|
)
|
|
562
562
|
end
|
|
563
563
|
|
|
564
|
+
# Whether this oga build honors the indent option (newer
|
|
565
|
+
# releases do; the capability probe keeps the indentation
|
|
566
|
+
# spec pending-or-live across both).
|
|
567
|
+
def indents_output?
|
|
568
|
+
return @indents_output unless @indents_output.nil?
|
|
569
|
+
|
|
570
|
+
probe = ::Oga::XML::Document.new
|
|
571
|
+
el = ::Oga::XML::Element.new(name: "r")
|
|
572
|
+
el.children << ::Oga::XML::Text.new(text: "t")
|
|
573
|
+
probe.children << el
|
|
574
|
+
@indents_output = serialize(probe, indent: 2).include?("
|
|
575
|
+
")
|
|
576
|
+
end
|
|
577
|
+
|
|
564
578
|
def serialize(node, options = {})
|
|
565
579
|
serialize_without_entity_processing(node, options)
|
|
566
580
|
end
|
data/lib/moxml/adapter/ox.rb
CHANGED
data/lib/moxml/adapter/rexml.rb
CHANGED
|
@@ -103,7 +103,7 @@ module Moxml
|
|
|
103
103
|
::REXML::Text.new(content.to_s, true, nil)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
def create_native_entity_reference(name)
|
|
106
|
+
def create_native_entity_reference(name, _owner_doc = nil)
|
|
107
107
|
::Moxml::Adapter::CustomizedRexml::EntityReference.new(name)
|
|
108
108
|
end
|
|
109
109
|
|
data/lib/moxml/config.rb
CHANGED
|
@@ -24,6 +24,13 @@ module Moxml
|
|
|
24
24
|
# - :optional - Try to load, continue silently if unavailable
|
|
25
25
|
# - :disabled - Don't load entities, use empty registry
|
|
26
26
|
# - :custom - Use custom entity provider via entity_provider callback
|
|
27
|
+
# Entity-reference preservation mode (leptris-ruby#212 / upstream
|
|
28
|
+
# #1094): :expand (default) keeps the shipped behavior (entities
|
|
29
|
+
# expanded at parse, marker-driven round-trip); :keep enables
|
|
30
|
+
# first-class EntityReference nodes and skips the marker machinery
|
|
31
|
+
# when the binding supports it (leptris >= 1.9.177).
|
|
32
|
+
ENTITY_MODES = %i[expand keep].freeze
|
|
33
|
+
|
|
27
34
|
ENTITY_LOAD_MODES = %i[required optional disabled custom].freeze
|
|
28
35
|
|
|
29
36
|
class << self
|
|
@@ -115,6 +122,7 @@ module Moxml
|
|
|
115
122
|
:entity_provider,
|
|
116
123
|
:namespace_validation_mode,
|
|
117
124
|
:entity_restoration_mode,
|
|
125
|
+
:entity_mode,
|
|
118
126
|
:ox_skip,
|
|
119
127
|
:ox_mode
|
|
120
128
|
|
|
@@ -165,6 +173,7 @@ module Moxml
|
|
|
165
173
|
@entity_provider = nil
|
|
166
174
|
@namespace_validation_mode = :strict
|
|
167
175
|
@entity_restoration_mode = :lenient
|
|
176
|
+
@entity_mode = :expand
|
|
168
177
|
end
|
|
169
178
|
|
|
170
179
|
def adapter=(name)
|
|
@@ -212,6 +221,16 @@ module Moxml
|
|
|
212
221
|
@namespace_validation_mode = mode
|
|
213
222
|
end
|
|
214
223
|
|
|
224
|
+
def entity_mode=(mode)
|
|
225
|
+
mode = mode.to_sym
|
|
226
|
+
unless ENTITY_MODES.include?(mode)
|
|
227
|
+
raise ArgumentError,
|
|
228
|
+
"Invalid entity_mode: #{mode.inspect}. Must be one of: #{ENTITY_MODES.join(', ')}"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
@entity_mode = mode
|
|
232
|
+
end
|
|
233
|
+
|
|
215
234
|
def entity_restoration_mode=(mode)
|
|
216
235
|
mode = mode.to_sym
|
|
217
236
|
unless ENTITY_RESTORATION_MODES.include?(mode)
|
data/lib/moxml/document.rb
CHANGED
|
@@ -99,7 +99,8 @@ module Moxml
|
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
def create_entity_reference(name)
|
|
102
|
-
|
|
102
|
+
native = adapter.create_entity_reference(name, @native)
|
|
103
|
+
Wrappers::EntityReference.new(native, context)
|
|
103
104
|
end
|
|
104
105
|
|
|
105
106
|
def add_child(node)
|
data/lib/moxml/version.rb
CHANGED
|
@@ -629,14 +629,46 @@ RSpec.describe Moxml::Adapter::Leptris do
|
|
|
629
629
|
expect(doc.at_xpath("//a").to_xml).to eq("<a>text</a>")
|
|
630
630
|
end
|
|
631
631
|
|
|
632
|
-
it "
|
|
633
|
-
|
|
634
|
-
|
|
632
|
+
it "validates entity_mode" do
|
|
633
|
+
config = Moxml::Config.new(:leptris)
|
|
634
|
+
config.entity_mode = :keep
|
|
635
635
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
636
|
+
expect(config.entity_mode).to eq(:keep)
|
|
637
|
+
expect { config.entity_mode = :invalid }.to raise_error(ArgumentError)
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
it "uses first-class entity references when requested on supported bindings" do
|
|
641
|
+
skip "requires leptris 1.9.177" unless described_class::NATIVE_ENTITY_REFS
|
|
642
|
+
|
|
643
|
+
keep_ctx = Moxml.new(:leptris) { |config| config.entity_mode = :keep }
|
|
644
|
+
doc = keep_ctx.parse("<root><a>pre & middle < post</a></root>")
|
|
645
|
+
children = doc.at_xpath("//a").children.to_a
|
|
646
|
+
|
|
647
|
+
expect(children.map(&:content)).to eq(["pre ", "", " middle ", "", " post"])
|
|
648
|
+
expect(children[1]).to be_a(Moxml::EntityReference)
|
|
649
|
+
expect(children[1].name).to eq("amp")
|
|
650
|
+
expect(children[3].name).to eq("lt")
|
|
651
|
+
expect(doc.to_xml).to include("pre & middle < post")
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
it "creates a first-class entity reference on supported bindings" do
|
|
655
|
+
skip "requires leptris 1.9.177" unless described_class::NATIVE_ENTITY_REFS
|
|
656
|
+
|
|
657
|
+
keep_ctx = Moxml.new(:leptris) { |config| config.entity_mode = :keep }
|
|
658
|
+
doc = keep_ctx.parse("<root><a/></root>")
|
|
659
|
+
reference = doc.create_entity_reference("copy")
|
|
660
|
+
doc.at_xpath("//a").add_child(reference)
|
|
661
|
+
|
|
662
|
+
expect(reference).to be_a(Moxml::EntityReference)
|
|
663
|
+
expect(reference.name).to eq("copy")
|
|
664
|
+
expect(doc.to_xml).to include("©")
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
it "keeps expansion as the default entity mode" do
|
|
668
|
+
doc = Moxml.new(:leptris).parse("<root>a & b</root>")
|
|
669
|
+
|
|
670
|
+
expect(doc.root.children.first).to be_a(Moxml::Text)
|
|
671
|
+
expect(doc.root.children.first.content).to eq("a & b")
|
|
640
672
|
end
|
|
641
673
|
end
|
|
642
674
|
|
|
@@ -334,7 +334,8 @@ RSpec.shared_examples "xml adapter" do
|
|
|
334
334
|
end
|
|
335
335
|
|
|
336
336
|
it "respects indentation settings" do
|
|
337
|
-
if described_class.name.include?("Oga")
|
|
337
|
+
if described_class.name.include?("Oga") &&
|
|
338
|
+
!described_class.indents_output?
|
|
338
339
|
pending("Oga does not support indentation settings")
|
|
339
340
|
end
|
|
340
341
|
if described_class.name.include?("Libxml")
|