moxml 0.5.25 → 0.5.27
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/serialize.rb +20 -6
- data/lib/moxml/version.rb +1 -1
- data/spec/moxml/adapter/leptris_spec.rb +30 -0
- 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: b9d156e4f8dfd71fc334b5626690f325a78abf95496bf19b6141bf649beeee58
|
|
4
|
+
data.tar.gz: 5f3c24b3211e8381d14a34c7c23781a808e2f55b1d73d06af3be0fe7d3640a75
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c5cd5d01ece3fcced5049148d2df776a1dcb9b1e95b0fe9a145caef05c0e2d5080b32214c7eb9f8f7bb277412827b413b3c59e38a49162241208944791a6ed6
|
|
7
|
+
data.tar.gz: 33faf5c9269c3c74a6def61ef3933a9bdc2caedf484e0144ca1c8e6465aeb1640bb47c3f44ce9c777ed5bbe8e9682efd840cb87d4eceedac764f4c496519fff3
|
|
@@ -85,24 +85,37 @@ module Moxml
|
|
|
85
85
|
# detection below is a no-op on correct builds.
|
|
86
86
|
RAW_AMP_RE = /&(?!#{Entity::NAME_PATTERN};|#\d+;|#x[0-9A-Fa-f]+;)/
|
|
87
87
|
|
|
88
|
+
# A raw "<" in text position — the engine intermittently
|
|
89
|
+
# loses the escape when parsing under allocation pressure
|
|
90
|
+
# (leptris-ruby#131), so a decoded < serializes bare and
|
|
91
|
+
# reparsing truncates at it. Valid markup NEVER puts "<"
|
|
92
|
+
# before a non-name, non-delimiter character, so this is
|
|
93
|
+
# deterministic in markup segments (CDATA is literal and
|
|
94
|
+
# excluded by the segment walker).
|
|
95
|
+
RAW_LT_RE = /<(?![A-Za-z_:\/?!])/
|
|
96
|
+
|
|
88
97
|
def normalize_serialization(xml, options)
|
|
89
98
|
# The libxml2-layout serializer (>= 1.9.42) keeps attribute
|
|
90
99
|
# apostrophes literal; older engines escaped them.
|
|
91
100
|
needs_apos = !LIBXML2_LAYOUT_PARITY && xml.include?("'")
|
|
92
101
|
needs_expand = options[:expand_empty] && xml.include?("/>")
|
|
93
|
-
|
|
94
|
-
|
|
102
|
+
# One scan each: both regexes fail fast on clean output.
|
|
103
|
+
needs_amp = xml.match?(RAW_AMP_RE)
|
|
104
|
+
needs_lt = xml.match?(RAW_LT_RE)
|
|
105
|
+
return xml unless needs_apos || needs_expand || needs_amp || needs_lt
|
|
95
106
|
|
|
96
107
|
out = +""
|
|
97
108
|
pos = 0
|
|
98
109
|
while pos < xml.length
|
|
99
110
|
opener_at, terminator = next_literal_region(xml, pos)
|
|
100
111
|
if opener_at.nil?
|
|
101
|
-
out << normalize_markup(xml[pos..], needs_apos, needs_expand,
|
|
112
|
+
out << normalize_markup(xml[pos..], needs_apos, needs_expand,
|
|
113
|
+
needs_amp: needs_amp, needs_lt: needs_lt)
|
|
102
114
|
break
|
|
103
115
|
end
|
|
104
116
|
|
|
105
|
-
out << normalize_markup(xml[pos...opener_at], needs_apos, needs_expand,
|
|
117
|
+
out << normalize_markup(xml[pos...opener_at], needs_apos, needs_expand,
|
|
118
|
+
needs_amp: needs_amp, needs_lt: needs_lt)
|
|
106
119
|
search_from = opener_at + opener_at_offset(terminator)
|
|
107
120
|
close = xml.index(terminator, search_from)
|
|
108
121
|
close_end = close.nil? ? xml.length : close + terminator.length
|
|
@@ -134,7 +147,7 @@ module Moxml
|
|
|
134
147
|
terminator == "-->" ? 4 : 0
|
|
135
148
|
end
|
|
136
149
|
|
|
137
|
-
def normalize_markup(markup, needs_apos, needs_expand, needs_amp: false)
|
|
150
|
+
def normalize_markup(markup, needs_apos, needs_expand, needs_amp: false, needs_lt: false)
|
|
138
151
|
markup = markup.gsub("'", "'") if needs_apos
|
|
139
152
|
if needs_expand
|
|
140
153
|
markup = markup.gsub(EMPTY_ELEMENT_RE) do
|
|
@@ -142,8 +155,9 @@ module Moxml
|
|
|
142
155
|
end
|
|
143
156
|
end
|
|
144
157
|
# Segment-aware: this never sees CDATA/comment/PI content,
|
|
145
|
-
# where
|
|
158
|
+
# where bare & and < are literal data.
|
|
146
159
|
markup = markup.gsub(RAW_AMP_RE, "&") if needs_amp
|
|
160
|
+
markup = markup.gsub(RAW_LT_RE, "<") if needs_lt
|
|
147
161
|
markup
|
|
148
162
|
end
|
|
149
163
|
end
|
data/lib/moxml/version.rb
CHANGED
|
@@ -243,6 +243,36 @@ RSpec.describe Moxml::Adapter::Leptris do
|
|
|
243
243
|
expect(doc.root.children.to_a.select(&:text?)).to be_empty
|
|
244
244
|
end
|
|
245
245
|
|
|
246
|
+
it "repairs a raw < in text position (issue #167 / leptris-ruby#131)" do
|
|
247
|
+
# The engine intermittently drops the escape when parsing under
|
|
248
|
+
# allocation pressure: a decoded < serializes bare and the
|
|
249
|
+
# output fails to reparse. Valid markup never puts < before a
|
|
250
|
+
# non-name character, so the damage is deterministically
|
|
251
|
+
# repairable in markup segments.
|
|
252
|
+
repaired = described_class.normalize_serialization(
|
|
253
|
+
%(<?xml version="1.0"?><r><pre>A <\n B</pre></r>\n), {}
|
|
254
|
+
)
|
|
255
|
+
expect(repaired).to include("A <")
|
|
256
|
+
expect(repaired).not_to match("A <")
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it "keeps a literal < inside CDATA untouched by the repair" do
|
|
260
|
+
doc = ctx.parse(%(<r><![CDATA[A < B]]></r>))
|
|
261
|
+
expect(doc.to_xml).to include("<![CDATA[A < B]]>")
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it "survives parse-under-allocation-pressure without emitting raw < (issue #167)" do
|
|
265
|
+
xml = "<?xml version=\"1.0\"?><doc>#{%(<s><pre alt="A B">A <\n B</pre></s>) * 10}</doc>"
|
|
266
|
+
30.times do
|
|
267
|
+
100.times { |j| "pressure#{j}" * 20 }
|
|
268
|
+
out = ctx.parse(xml, noblanks: true).to_xml(
|
|
269
|
+
declaration: true, encoding: "UTF-8", indent: 2, expand_empty: false,
|
|
270
|
+
)
|
|
271
|
+
expect(out).not_to match("A <"), "raw unescaped < leaked into text"
|
|
272
|
+
expect(Nokogiri::XML(out, &:strict)).to be_a(Nokogiri::XML::Document)
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
246
276
|
it "refuses noblanks on readonly parses while the strip path is active" do
|
|
247
277
|
# The strip mutates the tree; readonly freezes it at parse. On
|
|
248
278
|
# bindings whose engine flag is libxml2-safe (probe), the flag
|