leptris 1.9.57 → 1.9.58
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/CHANGELOG.md +57 -0
- data/README.adoc +36 -10
- data/Rakefile +1 -1
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/element.rb +4 -8
- data/lib/leptris/xml/ffi.rb +23 -5
- data/lib/leptris/xml/node.rb +13 -9
- data/lib/leptris/xml/node_set.rb +20 -4
- data/lib/leptris/xml/result_text.rb +36 -0
- data/lib/leptris/xml/serialization.rb +6 -9
- data/lib/leptris/xml.rb +19 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 159f07010d3dd22a62761daef970c4090a47ee9d7ba6471099380410119dadf2
|
|
4
|
+
data.tar.gz: b80e233d06f4d3af6bb14cc1cbf157ce88dfd7c745ffe7c936bc333d77b7e92d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2a1504b697e82a0eddeb8966597f2e39ba27362fa6ebdff2edf9dae2258f5a6cf5757b7088c144f69309ca5016297cba39513fe3a1a901b709029d82a45e88f
|
|
7
|
+
data.tar.gz: 4314c5cf903efe548acaec50494a40578e543f31268ffa9fcdee9e0bd9a069efa152bb8889ad86f6c43b638bd48ad7d554428e9ea9c48b1970301913aa905d66
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,63 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.58] - 2026-09-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Lockstep with libleptris 1.9.75** (1.9.68 → 1.9.75, eight
|
|
13
|
+
releases). One new C symbol attached (audit 260/260):
|
|
14
|
+
- **`Leptris::XML.parse_html`** (1.9.75, leptris/leptris#659 —
|
|
15
|
+
the last Nokogiri capability gap): tolerant HTML4/5 into the
|
|
16
|
+
STANDARD DOM — implied end tags, void elements, raw-text
|
|
17
|
+
script/style, lowercased names, minimized/unquoted attributes,
|
|
18
|
+
HTML named entities; html/head/body synthesized (Nokogiri::HTML
|
|
19
|
+
parity), tbody never implied; malformed markup degrades to
|
|
20
|
+
text. Eight specs; README HTML section; the migration list
|
|
21
|
+
drops "No Nokogiri::HTML".
|
|
22
|
+
- **XPath 2.0 ledger** (1.9.69/1.9.73, closes most of the #683
|
|
23
|
+
grammar list): value comparators (`eq`/`gt`/…), quantifiers
|
|
24
|
+
(`some`/`every`), set algebra (`intersect`/`except`), node
|
|
25
|
+
identity (`is`) — all standalone from `#xpath`, specced.
|
|
26
|
+
- **XQuery windows and typeswitch** (1.9.69/1.9.70): tumbling
|
|
27
|
+
and sliding `window` clauses, `typeswitch` dispatch, the error
|
|
28
|
+
code model (`try/catch` reaches its catch arm — the #790
|
|
29
|
+
cast-error piece landed). Specced.
|
|
30
|
+
- **Sequence items are readable**: `for … return`, sequence
|
|
31
|
+
literals, and XQuery constructor results arrive as
|
|
32
|
+
`Leptris::XML::ResultText` (new) — `#content` serves the value
|
|
33
|
+
directly, captured at result materialization through
|
|
34
|
+
`leptris_xpath_result_node_value` (the only accessor that can
|
|
35
|
+
read the engine's synthetic sequence carriers). The
|
|
36
|
+
"consume through an aggregate" caveat is retired.
|
|
37
|
+
- Upstream perf work adopted: AVT compile cache, keyed mutation
|
|
38
|
+
tail caches, fragment-output tail caches (1.9.71/1.9.72).
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **#130 closed** (dup degradation): the monotonic per-cycle rise
|
|
43
|
+
lived in the C-copy path — `dup` reverts to the serialization
|
|
44
|
+
round-trip (see #812 below) and the repro runs flat (~95 µs
|
|
45
|
+
per copy across 20 rounds × 15 copies).
|
|
46
|
+
- **#790 mostly fixed upstream** (1.9.68): constructor-as-return
|
|
47
|
+
parses (items arrive as readable serialized strings),
|
|
48
|
+
where/at-in-function-argument parses, cast errors reach
|
|
49
|
+
try/catch. Follow-up found and reported: the `where` clause is
|
|
50
|
+
silently IGNORED in the function-argument position (bare FLWOR
|
|
51
|
+
filters, wrapped does not) — one pending spec holds the correct
|
|
52
|
+
expectation.
|
|
53
|
+
- **leptris/leptris#812 filed** (1.9.74 copy rewrite regresses
|
|
54
|
+
#721): `leptris_element_copy` drops declarations used only by
|
|
55
|
+
descendants and resolution returns NULL on the copied subtree —
|
|
56
|
+
`dup` and the indent-unit path revert to the serialization
|
|
57
|
+
round-trip (byte-exact) until it lands.
|
|
58
|
+
- **leptris/leptris#815 filed** (from #131): the indenting
|
|
59
|
+
DOCUMENT serializer intermittently emits unescaped `<` in text
|
|
60
|
+
(invalid XML out) for ~5-7% of parses under allocation churn —
|
|
61
|
+
localized to the engine (all three C serialization paths corrupt;
|
|
62
|
+
`indent: 0` and the element face are clean). #131 stays open as
|
|
63
|
+
the tracker.
|
|
64
|
+
|
|
8
65
|
## [1.9.57] - 2026-09-03
|
|
9
66
|
|
|
10
67
|
### Changed
|
data/README.adoc
CHANGED
|
@@ -106,6 +106,26 @@ doc.root # => nil
|
|
|
106
106
|
Leptris::XML::FFI.leptris_last_error # => "..."
|
|
107
107
|
----
|
|
108
108
|
|
|
109
|
+
== HTML parsing
|
|
110
|
+
|
|
111
|
+
`Leptris::XML.parse_html(html)` parses tolerant HTML4/5 into a
|
|
112
|
+
standard Document — the same nodes, pool, serializer, and
|
|
113
|
+
XPath/XSLT/XQuery machinery as XML (libleptris 1.9.75, the last
|
|
114
|
+
Nokogiri capability gap):
|
|
115
|
+
|
|
116
|
+
[source,ruby]
|
|
117
|
+
----
|
|
118
|
+
doc = Leptris::XML.parse_html(%(<ul><li>a<li>b</ul>))
|
|
119
|
+
doc.at_css("body").inner_html # => "<ul><li>a</li><li>b</li></ul>"
|
|
120
|
+
----
|
|
121
|
+
|
|
122
|
+
Implied end tags (`p`/`li`/`td`/`tr`/...), void elements, raw-text
|
|
123
|
+
`<script>`/`<style>`, case-insensitive lowercased names,
|
|
124
|
+
minimized/unquoted attributes, and the HTML named entities all
|
|
125
|
+
parse; `html`/`head`/`body` are synthesized (Nokogiri::HTML parity)
|
|
126
|
+
but `tbody` is never implied. Malformed markup degrades to text
|
|
127
|
+
rather than raising.
|
|
128
|
+
|
|
109
129
|
== Reading nodes
|
|
110
130
|
|
|
111
131
|
[horizontal]
|
|
@@ -247,17 +267,21 @@ doc.xpath("[10, 20, 30]?2") # 3.1 arrays
|
|
|
247
267
|
doc.xpath(%q{serialize(parse-json('{"b":"beta"}'), map { 'method': 'json' })})
|
|
248
268
|
doc.xpath("function($x) { $x + 1 }(41)") # 3.1 function items
|
|
249
269
|
doc.xpath("fold-left(1 to 4, 0, function($a, $b) { $a + $b })")
|
|
270
|
+
doc.xpath("count(//a) eq 2") # 2.0 value comparators
|
|
271
|
+
doc.xpath("some $a in //a satisfies $a/@v > 1") # 2.0 quantifiers
|
|
272
|
+
doc.xpath("count(//a except //a[@v = 1])") # 2.0 set algebra
|
|
273
|
+
----
|
|
274
|
+
|
|
275
|
+
Sequence and constructor items arrive as `Leptris::XML::ResultText`
|
|
276
|
+
objects — `#content` serves the value directly:
|
|
277
|
+
|
|
278
|
+
[source,ruby]
|
|
279
|
+
----
|
|
280
|
+
doc.xpath("for $w in //a return string($w/@v)").map(&:content) # => ["1", "2"]
|
|
250
281
|
----
|
|
251
282
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
`string-join(...)`) until the engine materializes readable sequence
|
|
255
|
-
items; and XQuery-only syntax (`order by`, `try/catch`, map
|
|
256
|
-
constructors) raises `XPathError` rather than evaluating silently
|
|
257
|
-
wrong. The remaining grammar gaps — value comparators (`eq`),
|
|
258
|
-
quantifiers, `intersect`/`except`, string templates — and XQuery
|
|
259
|
-
itself are
|
|
260
|
-
https://github.com/leptris/leptris/issues/683[tracked upstream].
|
|
283
|
+
Remaining grammar gaps (https://github.com/leptris/leptris/issues/683[tracked
|
|
284
|
+
upstream]): 3.1 string templates, XQuery beyond the 1.0 core.
|
|
261
285
|
|
|
262
286
|
=== Supported CSS selectors
|
|
263
287
|
|
|
@@ -585,7 +609,9 @@ Notable differences:
|
|
|
585
609
|
Nokogiri is silent on this — migrating code that holds Node references
|
|
586
610
|
past Document disposal will see the error; silence-replace-UAF patterns
|
|
587
611
|
from Nokogiri do not apply.
|
|
588
|
-
* No `Nokogiri::
|
|
612
|
+
* No `Nokogiri::CSS` parser. HTML parsing is supported
|
|
613
|
+
(`Leptris::XML.parse_html`, libleptris 1.9.75); Nokogiri's
|
|
614
|
+
HTML-specific node subclasses have no equivalent.
|
|
589
615
|
* No RelaxNG / DTD validation, no schema caching (XSLT 1.0–3.0
|
|
590
616
|
and an XQuery 1.0 core are supported — see above).
|
|
591
617
|
* No built-in JRuby / TruffleRuby support — only CRuby via `ffi`.
|
data/Rakefile
CHANGED
|
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
|
8
8
|
# Pin for `rake compile` and the platform-gem builds. Keep in lockstep
|
|
9
9
|
# with .github/workflows/build.yml (which calls `rake compile`) and the
|
|
10
10
|
# CHANGELOG when libleptris releases.
|
|
11
|
-
LIBLEPTRIS_VERSION = "1.9.
|
|
11
|
+
LIBLEPTRIS_VERSION = "1.9.75"
|
|
12
12
|
|
|
13
13
|
CMAKE_FLAGS = %w[
|
|
14
14
|
-DCMAKE_BUILD_TYPE=Release
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/element.rb
CHANGED
|
@@ -251,16 +251,12 @@ class Leptris::XML::Element < Leptris::XML::Node
|
|
|
251
251
|
self
|
|
252
252
|
end
|
|
253
253
|
|
|
254
|
-
# Deep copy in a NEW document via
|
|
255
|
-
#
|
|
256
|
-
#
|
|
257
|
-
# root so the tree is fully navigable.
|
|
254
|
+
# Deep copy in a NEW document via serialization round-trip
|
|
255
|
+
# (leptris/leptris#812: the 1.9.74 copy rewrite drops
|
|
256
|
+
# descendant-used declarations; the serializer is byte-exact).
|
|
258
257
|
def dup
|
|
259
258
|
ensure_alive!
|
|
260
|
-
|
|
261
|
-
copy = Leptris::XML::FFI.leptris_element_copy(@c_ptr, new_doc.c_ptr)
|
|
262
|
-
raise Leptris::XML::Error, "leptris_element_copy failed" if copy.null?
|
|
263
|
-
new_doc.root = Leptris::XML::Node.wrap(copy, new_doc)
|
|
259
|
+
Leptris::XML::Document.parse(to_xml).root
|
|
264
260
|
end
|
|
265
261
|
alias_method :clone, :dup
|
|
266
262
|
|
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -133,7 +133,16 @@ module Leptris
|
|
|
133
133
|
attach_function :leptris_version, [], :string
|
|
134
134
|
attach_function :leptris_version_components, [:pointer, :pointer, :pointer], :void
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
# Tolerant HTML4/5 parse into the STANDARD DOM (libleptris
|
|
137
|
+
# 1.9.75, #659): implied end tags, void elements, raw-text
|
|
138
|
+
# script/style, case-insensitive (lowercased) names, the HTML
|
|
139
|
+
# named-entity table. Document shape — html/head/body
|
|
140
|
+
# synthesized; no implied tbody. Malformed input never fails
|
|
141
|
+
# the parse; only an entirely empty result is an error.
|
|
142
|
+
attach_function :leptris_parse_html_string,
|
|
143
|
+
[:string, :size_t, :pointer], :leptris_document
|
|
144
|
+
|
|
145
|
+
attach_function :leptris_parse_string,
|
|
137
146
|
[:string, :size_t, :pointer], :leptris_document
|
|
138
147
|
attach_function :leptris_parse_string_flags,
|
|
139
148
|
[:string, :size_t, :uint, :pointer], :leptris_document
|
|
@@ -780,6 +789,11 @@ module Leptris
|
|
|
780
789
|
NODE_COMMENT = 2
|
|
781
790
|
NODE_CDATA = 3
|
|
782
791
|
NODE_PI = 4
|
|
792
|
+
# Internal XPath-synthetic text node (leptris/types.h): the
|
|
793
|
+
# carrier for sequence/map/array items in result nodesets —
|
|
794
|
+
# readable only through the result handle, so the binding
|
|
795
|
+
# captures the value at materialization (ResultText).
|
|
796
|
+
NODE_SYNTHETIC_TEXT = 8
|
|
783
797
|
NODE_DOCTYPE = 5
|
|
784
798
|
NODE_ATTRIBUTE = 6
|
|
785
799
|
|
|
@@ -1070,15 +1084,19 @@ module Leptris
|
|
|
1070
1084
|
# get_type in the wrapper. Returns [pointers, element_hints].
|
|
1071
1085
|
XPATH_KIND_HINT = { XPATH_NODE_ELEMENT => NODE_ELEMENT }.freeze
|
|
1072
1086
|
|
|
1087
|
+
# Returns [pointers, element_hints, raw_kinds] — the raw
|
|
1088
|
+
# XPATH_NODE-space kinds ride along so the materializer can
|
|
1089
|
+
# spot TEXT items (synthetic sequence carriers) and capture
|
|
1090
|
+
# their values while the result handle is alive.
|
|
1073
1091
|
def self.fetch_result_nodes(result_ptr, count)
|
|
1074
|
-
return [[], nil] if count.zero?
|
|
1092
|
+
return [[], nil, nil] if count.zero?
|
|
1075
1093
|
buffer = scratch_pointers(count)
|
|
1076
1094
|
kinds = scratch_ints(count)
|
|
1077
1095
|
copied = leptris_xpath_result_get_nodes_ex(
|
|
1078
1096
|
result_ptr, buffer, kinds, count)
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
[buffer.get_array_of_pointer(0, copied), hints]
|
|
1097
|
+
raw = kinds.get_array_of_int(0, copied)
|
|
1098
|
+
hints = raw.map { |k| XPATH_KIND_HINT[k] }
|
|
1099
|
+
[buffer.get_array_of_pointer(0, copied), hints, raw]
|
|
1082
1100
|
end
|
|
1083
1101
|
|
|
1084
1102
|
# Fragment parse with the status out-param read: returns
|
data/lib/leptris/xml/node.rb
CHANGED
|
@@ -15,7 +15,7 @@ class Leptris::XML::Node
|
|
|
15
15
|
# node_type: callers holding a batch-fetched kind (the XPath
|
|
16
16
|
# result-set batch fills out_kinds) pass it so the wrap skips the
|
|
17
17
|
# get_type dispatch; nil (the default) dispatches as before.
|
|
18
|
-
def self.wrap(c_ptr, document, parent: nil, node_type: nil)
|
|
18
|
+
def self.wrap(c_ptr, document, parent: nil, node_type: nil, result_value: nil)
|
|
19
19
|
# Per-document weak-ref cache. Returns the existing wrapper when the
|
|
20
20
|
# same c_ptr is wrapped twice (common in children/sibling walks,
|
|
21
21
|
# repeated xpath queries, traverse-then-access patterns). The cache
|
|
@@ -37,6 +37,11 @@ class Leptris::XML::Node
|
|
|
37
37
|
Leptris::XML::Element.new(c_ptr, document, parent: parent, node_type: node_type)
|
|
38
38
|
when Leptris::XML::FFI::NODE_TEXT
|
|
39
39
|
Leptris::XML::Text.new(c_ptr, document, parent: parent, node_type: node_type)
|
|
40
|
+
when Leptris::XML::FFI::NODE_SYNTHETIC_TEXT
|
|
41
|
+
# Sequence/map/array items: value captured by the NodeSet at
|
|
42
|
+
# materialization (only the result handle can read them).
|
|
43
|
+
Leptris::XML::ResultText.new(
|
|
44
|
+
c_ptr, document, result_value, parent: parent, node_type: node_type)
|
|
40
45
|
when Leptris::XML::FFI::NODE_COMMENT
|
|
41
46
|
Leptris::XML::Comment.new(c_ptr, document, parent: parent, node_type: node_type)
|
|
42
47
|
when Leptris::XML::FFI::NODE_CDATA
|
|
@@ -369,18 +374,17 @@ class Leptris::XML::Node
|
|
|
369
374
|
result
|
|
370
375
|
end
|
|
371
376
|
|
|
372
|
-
# Deep copy in a NEW document
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
377
|
+
# Deep copy in a NEW document. Rounds through serialization: the
|
|
378
|
+
# 1.9.74 copy rewrite (#653 perf lane) drops declarations used
|
|
379
|
+
# only by descendants — resolution on the copied subtree resolves
|
|
380
|
+
# NULL (leptris/leptris#812, an #721 regression) — while the
|
|
381
|
+
# serializer preserves every child kind, prefixed name, and
|
|
382
|
+
# declaration byte-for-byte.
|
|
376
383
|
def dup
|
|
377
384
|
ensure_alive!
|
|
378
385
|
elem_ptr = Leptris::XML::FFI.leptris_node_as_element(@c_ptr)
|
|
379
386
|
raise Leptris::XML::Error, "dup is only supported for element nodes" if elem_ptr.null?
|
|
380
|
-
|
|
381
|
-
copy = Leptris::XML::FFI.leptris_element_copy(elem_ptr, new_doc.c_ptr)
|
|
382
|
-
raise Leptris::XML::Error, "leptris_element_copy failed" if copy.null?
|
|
383
|
-
new_doc.root = Leptris::XML::Node.wrap(copy, new_doc)
|
|
387
|
+
Leptris::XML::Document.parse(to_xml).root
|
|
384
388
|
end
|
|
385
389
|
alias_method :clone, :dup
|
|
386
390
|
|
data/lib/leptris/xml/node_set.rb
CHANGED
|
@@ -62,10 +62,21 @@ class Leptris::XML::NodeSet
|
|
|
62
62
|
if @result_ptr
|
|
63
63
|
ptr = Leptris::XML::FFI.leptris_xpath_result_get_node(@result_ptr, idx)
|
|
64
64
|
return nil if ptr.null?
|
|
65
|
-
Leptris::XML::Node.wrap(
|
|
65
|
+
Leptris::XML::Node.wrap(
|
|
66
|
+
ptr, @document,
|
|
67
|
+
result_value: text_item_value(
|
|
68
|
+
Leptris::XML::FFI.leptris_xpath_result_node_kind(@result_ptr, idx), idx))
|
|
66
69
|
end
|
|
67
70
|
end
|
|
68
71
|
|
|
72
|
+
# Sequence/map/array items ride synthetic text nodes whose value
|
|
73
|
+
# only the live result handle can serve — capture it now.
|
|
74
|
+
def text_item_value(kind, index)
|
|
75
|
+
return nil unless kind == Leptris::XML::FFI::XPATH_NODE_TEXT
|
|
76
|
+
Leptris::XML::FFI.leptris_xpath_result_node_value(@result_ptr, index)
|
|
77
|
+
end
|
|
78
|
+
private :text_item_value
|
|
79
|
+
|
|
69
80
|
# Iteration materializes: the first pass batch-fetches into @array
|
|
70
81
|
# (yielding as it wraps), and every subsequent reader — each, [],
|
|
71
82
|
# length — serves from the array. Repeated iteration without an
|
|
@@ -81,16 +92,21 @@ class Leptris::XML::NodeSet
|
|
|
81
92
|
# not just elements); the batch accessor under-copies
|
|
82
93
|
# mixed-kind results (upstream leptris#477), so per-index
|
|
83
94
|
# fetch covers the remainder.
|
|
84
|
-
pointers, kinds = Leptris::XML::FFI.fetch_result_nodes(@result_ptr, n)
|
|
95
|
+
pointers, kinds, raw = Leptris::XML::FFI.fetch_result_nodes(@result_ptr, n)
|
|
85
96
|
nodes = []
|
|
86
97
|
pointers.each_with_index do |ptr, i|
|
|
87
98
|
next if ptr.null?
|
|
88
|
-
nodes << Leptris::XML::Node.wrap(
|
|
99
|
+
nodes << Leptris::XML::Node.wrap(
|
|
100
|
+
ptr, @document, node_type: kinds[i],
|
|
101
|
+
result_value: text_item_value(raw[i], i))
|
|
89
102
|
end
|
|
90
103
|
(pointers.length...n).each do |i|
|
|
91
104
|
ptr = Leptris::XML::FFI.leptris_xpath_result_get_node(@result_ptr, i)
|
|
92
105
|
next if ptr.null?
|
|
93
|
-
nodes << Leptris::XML::Node.wrap(
|
|
106
|
+
nodes << Leptris::XML::Node.wrap(
|
|
107
|
+
ptr, @document,
|
|
108
|
+
result_value: text_item_value(
|
|
109
|
+
Leptris::XML::FFI.leptris_xpath_result_node_kind(@result_ptr, i), i))
|
|
94
110
|
end
|
|
95
111
|
@array = nodes
|
|
96
112
|
else
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Text-kind item from an XPath/XQuery sequence result: the engine
|
|
4
|
+
# materializes sequence, map, and array items as synthetic text
|
|
5
|
+
# nodes (leptris/types.h's internal kind 8) whose value is readable
|
|
6
|
+
# only through the live result handle — the node-pointer accessors
|
|
7
|
+
# return nothing for them. The NodeSet therefore captures the string
|
|
8
|
+
# value at materialization time and hands it to this wrapper.
|
|
9
|
+
#
|
|
10
|
+
# doc.xpath("for $w in //a return string($w/@v)").map(&:content)
|
|
11
|
+
# # => ["1", "2"]
|
|
12
|
+
#
|
|
13
|
+
class Leptris::XML::ResultText < Leptris::XML::Node
|
|
14
|
+
def initialize(c_ptr, document, value, parent: nil, node_type: nil)
|
|
15
|
+
super(c_ptr, document, parent: parent, node_type: node_type)
|
|
16
|
+
@value = value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def name
|
|
20
|
+
"text"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# The captured string: safe to read even after the owning result
|
|
24
|
+
# set has been collected (unlike pointer-backed reads).
|
|
25
|
+
def content
|
|
26
|
+
@value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
@value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def text?
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -115,17 +115,14 @@ module Leptris::XML::Serialization
|
|
|
115
115
|
|
|
116
116
|
# Element-face indent unit (leptris-ruby#109 residual 2): no
|
|
117
117
|
# element-level ext-serialize entry exists yet, so the unit path
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
# #
|
|
121
|
-
# identical output to the element serializer for
|
|
122
|
-
# layout, with the unit and every child kind intact.
|
|
118
|
+
# rounds the subtree through serialization into a fresh document
|
|
119
|
+
# (the 1.9.74 C copy drops descendant-used declarations —
|
|
120
|
+
# leptris/leptris#812) and serializes that document without a
|
|
121
|
+
# declaration — identical output to the element serializer for
|
|
122
|
+
# the standard layout, with the unit and every child kind intact.
|
|
123
123
|
def self.to_xml_element_unit(element, unit, indent: 0)
|
|
124
|
-
document = Leptris::XML::Document.
|
|
124
|
+
document = Leptris::XML::Document.parse(element.to_xml)
|
|
125
125
|
begin
|
|
126
|
-
copy = Leptris::XML::FFI.leptris_element_copy(element.c_ptr, document.c_ptr)
|
|
127
|
-
raise Leptris::XML::Error, "leptris_element_copy failed" if copy.null?
|
|
128
|
-
document.root = Leptris::XML::Node.wrap(copy, document)
|
|
129
126
|
to_xml_indent_unit(document.c_ptr, unit,
|
|
130
127
|
indent: indent, no_decl: true)
|
|
131
128
|
ensure
|
data/lib/leptris/xml.rb
CHANGED
|
@@ -22,6 +22,7 @@ module Leptris
|
|
|
22
22
|
autoload :Serialization, "leptris/xml/serialization"
|
|
23
23
|
autoload :SAX, "leptris/xml/sax"
|
|
24
24
|
autoload :XPath, "leptris/xml/xpath"
|
|
25
|
+
autoload :ResultText, "leptris/xml/result_text"
|
|
25
26
|
autoload :XSLT, "leptris/xml/xslt"
|
|
26
27
|
autoload :XQuery, "leptris/xml/xquery"
|
|
27
28
|
autoload :Pull, "leptris/xml/pull"
|
|
@@ -44,6 +45,24 @@ module Leptris
|
|
|
44
45
|
string, string.bytesize) != 0
|
|
45
46
|
end
|
|
46
47
|
|
|
48
|
+
# Tolerant HTML4/5 parse into a standard Document (libleptris
|
|
49
|
+
# 1.9.75): implied end tags, void elements, raw-text script and
|
|
50
|
+
# style, lowercased names, minimized/unquoted attributes, and
|
|
51
|
+
# the HTML named entities. Document shape — html/head/body are
|
|
52
|
+
# synthesized (Nokogiri::HTML parity), but NO implied tbody.
|
|
53
|
+
# Malformed input degrades to text rather than raising; only an
|
|
54
|
+
# entirely empty result is an error.
|
|
55
|
+
def self.parse_html(html)
|
|
56
|
+
html = html.to_s
|
|
57
|
+
raw = Leptris::XML::FFI.leptris_parse_html_string(
|
|
58
|
+
html, html.bytesize, nil)
|
|
59
|
+
if raw.null?
|
|
60
|
+
raise Leptris::XML::ParseError,
|
|
61
|
+
"HTML parse failed: #{Leptris::XML::FFI.leptris_last_error}"
|
|
62
|
+
end
|
|
63
|
+
Leptris::XML::Document.wrap(raw)
|
|
64
|
+
end
|
|
65
|
+
|
|
47
66
|
def self.parse_file(path)
|
|
48
67
|
Document.parse_file(path)
|
|
49
68
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: leptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.
|
|
4
|
+
version: 1.9.58
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -96,6 +96,7 @@ files:
|
|
|
96
96
|
- lib/leptris/xml/parse_options.rb
|
|
97
97
|
- lib/leptris/xml/processing_instruction.rb
|
|
98
98
|
- lib/leptris/xml/pull.rb
|
|
99
|
+
- lib/leptris/xml/result_text.rb
|
|
99
100
|
- lib/leptris/xml/sax.rb
|
|
100
101
|
- lib/leptris/xml/sax/document.rb
|
|
101
102
|
- lib/leptris/xml/sax/dom_dispatch.rb
|