/
document_fragment.rb
162 lines (142 loc) · 4.72 KB
/
document_fragment.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# frozen_string_literal: true
module Nokogiri
module XML
class DocumentFragment < Nokogiri::XML::Node
####
# Create a Nokogiri::XML::DocumentFragment from +tags+
def self.parse(tags, options = ParseOptions::DEFAULT_XML, &block)
new(XML::Document.new, tags, nil, options, &block)
end
##
# Create a new DocumentFragment from +tags+.
#
# If +ctx+ is present, it is used as a context node for the
# subtree created, e.g., namespaces will be resolved relative
# to +ctx+.
def initialize(document, tags = nil, ctx = nil, options = ParseOptions::DEFAULT_XML)
return self unless tags
options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
yield options if block_given?
children = if ctx
# Fix for issue#490
if Nokogiri.jruby?
# fix for issue #770
ctx.parse("<root #{namespace_declarations(ctx)}>#{tags}</root>", options).children
else
ctx.parse(tags, options)
end
else
wrapper_doc = XML::Document.parse("<root>#{tags}</root>", nil, nil, options)
self.errors = wrapper_doc.errors
wrapper_doc.xpath("/root/node()")
end
children.each { |child| child.parent = self }
end
if Nokogiri.uses_libxml?
def dup
new_document = document.dup
new_fragment = self.class.new(new_document)
children.each do |child|
child.dup(1, new_document).parent = new_fragment
end
new_fragment
end
end
###
# return the name for DocumentFragment
def name
"#document-fragment"
end
###
# Convert this DocumentFragment to a string
def to_s
children.to_s
end
###
# Convert this DocumentFragment to html
# See Nokogiri::XML::NodeSet#to_html
def to_html(*args)
if Nokogiri.jruby?
options = args.first.is_a?(Hash) ? args.shift : {}
unless options[:save_with]
options[:save_with] = Node::SaveOptions::NO_DECLARATION | Node::SaveOptions::NO_EMPTY_TAGS | Node::SaveOptions::AS_HTML
end
args.insert(0, options)
end
children.to_html(*args)
end
###
# Convert this DocumentFragment to xhtml
# See Nokogiri::XML::NodeSet#to_xhtml
def to_xhtml(*args)
if Nokogiri.jruby?
options = args.first.is_a?(Hash) ? args.shift : {}
unless options[:save_with]
options[:save_with] = Node::SaveOptions::NO_DECLARATION | Node::SaveOptions::NO_EMPTY_TAGS | Node::SaveOptions::AS_XHTML
end
args.insert(0, options)
end
children.to_xhtml(*args)
end
###
# Convert this DocumentFragment to xml
# See Nokogiri::XML::NodeSet#to_xml
def to_xml(*args)
children.to_xml(*args)
end
###
# call-seq: css *rules, [namespace-bindings, custom-pseudo-class]
#
# Search this fragment for CSS +rules+. +rules+ must be one or more CSS
# selectors. For example:
#
# For more information see Nokogiri::XML::Searchable#css
def css(*args)
if children.any?
children.css(*args) # 'children' is a smell here
else
NodeSet.new(document)
end
end
#
# NOTE that we don't delegate #xpath to children ... another smell.
# def xpath ; end
#
###
# call-seq: search *paths, [namespace-bindings, xpath-variable-bindings, custom-handler-class]
#
# Search this fragment for +paths+. +paths+ must be one or more XPath or CSS queries.
#
# For more information see Nokogiri::XML::Searchable#search
def search(*rules)
rules, handler, ns, binds = extract_params(rules)
rules.inject(NodeSet.new(document)) do |set, rule|
set + if Searchable::LOOKS_LIKE_XPATH.match?(rule)
xpath(*[rule, ns, handler, binds].compact)
else
children.css(*[rule, ns, handler].compact) # 'children' is a smell here
end
end
end
alias_method :serialize, :to_s
# A list of Nokogiri::XML::SyntaxError found when parsing a document
def errors
document.errors
end
def errors=(things) # :nodoc:
document.errors = things
end
def fragment(data)
document.fragment(data)
end
private
# fix for issue 770
def namespace_declarations(ctx)
ctx.namespace_scopes.map do |namespace|
prefix = namespace.prefix.nil? ? "" : ":#{namespace.prefix}"
%{xmlns#{prefix}="#{namespace.href}"}
end.join(" ")
end
end
end
end