moxml 0.4.0 → 0.5.1
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.rb +23 -22
- data/lib/moxml/adapter/libxml.rb +5 -1
- data/lib/moxml/adapter/ox.rb +41 -21
- data/lib/moxml/adapter/rexml.rb +9 -5
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml/xpath/compiler.rb +0 -4
- 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: ca6fefbf114afcaf13d9c241b4df5081eef1e004019618ca12d31a655d89dd53
|
|
4
|
+
data.tar.gz: d361373f16dafff997d4ca53b5dbc23c332b09331e8f49ef5abed09f526bdea7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a2e61a613511970e4c6945c074a578aefcb12591def797a726bf0959796c43dbf2e71b77509271b1dad15b9f0f1e81f5ec3b8b0af0e384bccad35745bc2dbb6
|
|
7
|
+
data.tar.gz: 183964ef083c888b3b7d58b896a547acf25c0414d997040c10b805b8379088825c2ec996b149aa9e8fe51b6419135d1341d8ebe9c88ddb0656101e25d3291557
|
|
@@ -266,7 +266,13 @@ module Moxml
|
|
|
266
266
|
def split_entity_markers(natives, parent)
|
|
267
267
|
result = []
|
|
268
268
|
natives.each do |child|
|
|
269
|
-
|
|
269
|
+
# FFI Text#content returns a fresh unfrozen BINARY string:
|
|
270
|
+
# retag in place (dup would be a throwaway allocation), but
|
|
271
|
+
# before include? — BINARY.include? with the UTF-8 marker raises
|
|
272
|
+
if child.is_a?(::Leptris::XML::Text)
|
|
273
|
+
content = child.content
|
|
274
|
+
content.force_encoding("UTF-8")
|
|
275
|
+
end
|
|
270
276
|
if content&.include?(Entity::MARKER)
|
|
271
277
|
content.scan(/([^#{Entity::MARKER}]*)(?:#{Entity::MARKER}([\w.:-]+);)?/o) do
|
|
272
278
|
text_part = Regexp.last_match(1)
|
|
@@ -852,26 +858,6 @@ module Moxml
|
|
|
852
858
|
XmlEmitter.doctype_xml(dt.root_name, dt.public_id, dt.system_id)
|
|
853
859
|
end
|
|
854
860
|
|
|
855
|
-
def entity_refs?(element)
|
|
856
|
-
element.is_a?(::Leptris::XML::Element) &&
|
|
857
|
-
!attachments.get(element, :entity_refs).to_a.empty?
|
|
858
|
-
end
|
|
859
|
-
|
|
860
|
-
# Registry-based entity references are not in the native tree,
|
|
861
|
-
# so the native serializer cannot see them; compose the element
|
|
862
|
-
# from the wrapper-visible children instead.
|
|
863
|
-
def serialize_entity_bearing_element(element, options)
|
|
864
|
-
name = element.prefix ? "#{element.prefix}:#{element.name}" : element.name
|
|
865
|
-
attrs = element.attribute_nodes.map do |attr|
|
|
866
|
-
%( #{attr.name}="#{XmlEmitter.escape_attribute(attr.value)}")
|
|
867
|
-
end.join
|
|
868
|
-
decls = element.namespace_definitions.map do |ns|
|
|
869
|
-
ns.prefix ? %( xmlns:#{ns.prefix}="#{ns.href}") : %( xmlns="#{ns.href}")
|
|
870
|
-
end.join
|
|
871
|
-
inner = children(element).map { |child| raw_serialize(child, options) }.join
|
|
872
|
-
"<#{name}#{decls}#{attrs}>#{inner}</#{name}>"
|
|
873
|
-
end
|
|
874
|
-
|
|
875
861
|
def sax_parse(xml, handler)
|
|
876
862
|
bridge = LeptrisSAXBridge.new(handler)
|
|
877
863
|
xml_string = xml.is_a?(IO) || xml.is_a?(::StringIO) ? xml.read : xml.to_s
|
|
@@ -882,8 +868,23 @@ module Moxml
|
|
|
882
868
|
|
|
883
869
|
private
|
|
884
870
|
|
|
871
|
+
# The variable-length \s* gap after \A defeats Onigmo's anchor
|
|
872
|
+
# optimization, forcing a full-buffer scan — 6.5 ms on a 1 MB
|
|
873
|
+
# document without a declaration (the common case). Match a
|
|
874
|
+
# head slice instead; fall back to the full string only when
|
|
875
|
+
# the head is all whitespace (pathological prefixes).
|
|
876
|
+
SOURCE_DECLARATION_RE = /\A\s*<\?xml\b/
|
|
877
|
+
private_constant :SOURCE_DECLARATION_RE
|
|
878
|
+
|
|
885
879
|
def record_source_declaration(native_doc, xml_string)
|
|
886
|
-
|
|
880
|
+
head = xml_string[0, 256]
|
|
881
|
+
had = if head.match?(SOURCE_DECLARATION_RE)
|
|
882
|
+
true
|
|
883
|
+
elsif head.match?(/\A\s*\z/)
|
|
884
|
+
xml_string.match?(SOURCE_DECLARATION_RE)
|
|
885
|
+
else
|
|
886
|
+
false
|
|
887
|
+
end
|
|
887
888
|
attachments.set(native_doc, :had_source_declaration, had)
|
|
888
889
|
end
|
|
889
890
|
|
data/lib/moxml/adapter/libxml.rb
CHANGED
|
@@ -1060,6 +1060,11 @@ module Moxml
|
|
|
1060
1060
|
# output keeps the walker.
|
|
1061
1061
|
return nil if output.include?("xmlns")
|
|
1062
1062
|
|
|
1063
|
+
# The native serializer escapes non-ASCII codepoints in
|
|
1064
|
+
# attribute values as numeric character references
|
|
1065
|
+
# (x="©"); the walker emits literal UTF-8
|
|
1066
|
+
return nil if output.include?("&#x")
|
|
1067
|
+
|
|
1063
1068
|
# Layout: pull closing tags onto the last child's line
|
|
1064
1069
|
output = output.gsub(/\n[ \t]*(<\/[\w.:-]+>)/, '\1')
|
|
1065
1070
|
|
|
@@ -1073,7 +1078,6 @@ module Moxml
|
|
|
1073
1078
|
|
|
1074
1079
|
# Native escapes attribute apostrophes; moxml keeps them literal
|
|
1075
1080
|
output.gsub("'", "'")
|
|
1076
|
-
|
|
1077
1081
|
end
|
|
1078
1082
|
|
|
1079
1083
|
# Shallow duplication: copies the node itself (name, attrs, namespaces)
|
data/lib/moxml/adapter/ox.rb
CHANGED
|
@@ -717,28 +717,48 @@ module Moxml
|
|
|
717
717
|
# Only documents/elements can contain entity refs or CDATA issues
|
|
718
718
|
return false unless node.is_a?(::Ox::Document) || node.is_a?(::Ox::Element)
|
|
719
719
|
|
|
720
|
-
#
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
has_cdata =
|
|
736
|
-
if
|
|
737
|
-
attachments.set(
|
|
738
|
-
attachments.set(
|
|
720
|
+
# Element serializes consult the owning document's cached
|
|
721
|
+
# flags — a rescan per call made element to_xml ~30x slower
|
|
722
|
+
# than document to_xml on plain documents.
|
|
723
|
+
scan_root = node
|
|
724
|
+
if node.is_a?(::Ox::Element) && (doc = document(node))
|
|
725
|
+
return true if attachments.get(doc, :has_entity_refs)
|
|
726
|
+
return true if attachments.get(doc, :has_cdata_end_markers)
|
|
727
|
+
return false if attachments.key?(doc, :has_entity_refs) &&
|
|
728
|
+
attachments.key?(doc, :has_cdata_end_markers)
|
|
729
|
+
|
|
730
|
+
scan_root = doc
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
# One merged tree scan instead of two; flags cache on the
|
|
734
|
+
# document either way.
|
|
735
|
+
has_er, has_cdata = tree_scan_custom_needs(scan_root)
|
|
736
|
+
if scan_root.is_a?(::Ox::Document)
|
|
737
|
+
attachments.set(scan_root, :has_entity_refs, has_er)
|
|
738
|
+
attachments.set(scan_root, :has_cdata_end_markers, has_cdata)
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
has_er || has_cdata
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
# Single walk collecting both custom-serialize triggers.
|
|
745
|
+
def tree_scan_custom_needs(node)
|
|
746
|
+
has_er = false
|
|
747
|
+
has_cdata = false
|
|
748
|
+
stack = [node]
|
|
749
|
+
until stack.empty?
|
|
750
|
+
current = stack.pop
|
|
751
|
+
case current
|
|
752
|
+
when ::Moxml::Adapter::CustomizedOx::EntityReference
|
|
753
|
+
has_er = true
|
|
754
|
+
when ::Ox::CData
|
|
755
|
+
has_cdata = true if current.value&.include?("]]>")
|
|
756
|
+
when ::Ox::Element, ::Ox::Document
|
|
757
|
+
current.nodes&.each { |child| stack << child }
|
|
758
|
+
end
|
|
759
|
+
return [true, has_cdata] if has_er
|
|
739
760
|
end
|
|
740
|
-
|
|
741
|
-
has_cdata
|
|
761
|
+
[has_er, has_cdata]
|
|
742
762
|
end
|
|
743
763
|
|
|
744
764
|
def has_declaration?(native_doc, _wrapper)
|
data/lib/moxml/adapter/rexml.rb
CHANGED
|
@@ -186,12 +186,16 @@ module Moxml
|
|
|
186
186
|
# Return all children preserving whitespace text nodes
|
|
187
187
|
result = node.children.dup
|
|
188
188
|
|
|
189
|
-
# Include any EntityReference wrappers stored alongside native
|
|
189
|
+
# Include any EntityReference wrappers stored alongside native
|
|
190
|
+
# children. Native children are identity-unique; only this
|
|
191
|
+
# concat can duplicate (the same wrapper added twice), so the
|
|
192
|
+
# dedupe lives here and the common path stays scan-free.
|
|
190
193
|
entity_refs = attachments.get(node, :entity_refs)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
if entity_refs
|
|
195
|
+
result.concat(entity_refs).uniq!(&:object_id) || result
|
|
196
|
+
else
|
|
197
|
+
result
|
|
198
|
+
end
|
|
195
199
|
end
|
|
196
200
|
|
|
197
201
|
def parent(node)
|
data/lib/moxml/version.rb
CHANGED
data/lib/moxml/xpath/compiler.rb
CHANGED