nokogiri 1.11.0.rc1-java → 1.11.2-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/LICENSE-DEPENDENCIES.md +1015 -947
  4. data/LICENSE.md +1 -1
  5. data/README.md +171 -94
  6. data/ext/java/nokogiri/EncodingHandler.java +78 -59
  7. data/ext/java/nokogiri/HtmlDocument.java +137 -114
  8. data/ext/java/nokogiri/HtmlElementDescription.java +104 -87
  9. data/ext/java/nokogiri/HtmlEntityLookup.java +31 -26
  10. data/ext/java/nokogiri/HtmlSaxParserContext.java +220 -192
  11. data/ext/java/nokogiri/HtmlSaxPushParser.java +164 -139
  12. data/ext/java/nokogiri/NokogiriService.java +597 -526
  13. data/ext/java/nokogiri/XmlAttr.java +120 -96
  14. data/ext/java/nokogiri/XmlAttributeDecl.java +97 -76
  15. data/ext/java/nokogiri/XmlCdata.java +35 -26
  16. data/ext/java/nokogiri/XmlComment.java +48 -37
  17. data/ext/java/nokogiri/XmlDocument.java +642 -540
  18. data/ext/java/nokogiri/XmlDocumentFragment.java +127 -107
  19. data/ext/java/nokogiri/XmlDtd.java +450 -384
  20. data/ext/java/nokogiri/XmlElement.java +25 -18
  21. data/ext/java/nokogiri/XmlElementContent.java +345 -286
  22. data/ext/java/nokogiri/XmlElementDecl.java +126 -95
  23. data/ext/java/nokogiri/XmlEntityDecl.java +121 -97
  24. data/ext/java/nokogiri/XmlEntityReference.java +51 -42
  25. data/ext/java/nokogiri/XmlNamespace.java +177 -145
  26. data/ext/java/nokogiri/XmlNode.java +1843 -1590
  27. data/ext/java/nokogiri/XmlNodeSet.java +361 -299
  28. data/ext/java/nokogiri/XmlProcessingInstruction.java +49 -39
  29. data/ext/java/nokogiri/XmlReader.java +513 -418
  30. data/ext/java/nokogiri/XmlRelaxng.java +92 -72
  31. data/ext/java/nokogiri/XmlSaxParserContext.java +330 -280
  32. data/ext/java/nokogiri/XmlSaxPushParser.java +229 -190
  33. data/ext/java/nokogiri/XmlSchema.java +335 -210
  34. data/ext/java/nokogiri/XmlSyntaxError.java +113 -87
  35. data/ext/java/nokogiri/XmlText.java +57 -46
  36. data/ext/java/nokogiri/XmlXpathContext.java +242 -178
  37. data/ext/java/nokogiri/XsltStylesheet.java +282 -239
  38. data/ext/java/nokogiri/internals/ClosedStreamException.java +5 -2
  39. data/ext/java/nokogiri/internals/HtmlDomParserContext.java +203 -160
  40. data/ext/java/nokogiri/internals/IgnoreSchemaErrorsErrorHandler.java +17 -10
  41. data/ext/java/nokogiri/internals/NokogiriBlockingQueueInputStream.java +43 -16
  42. data/ext/java/nokogiri/internals/NokogiriDomParser.java +65 -50
  43. data/ext/java/nokogiri/internals/NokogiriEntityResolver.java +107 -88
  44. data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +25 -18
  45. data/ext/java/nokogiri/internals/NokogiriHandler.java +316 -254
  46. data/ext/java/nokogiri/internals/NokogiriHelpers.java +738 -622
  47. data/ext/java/nokogiri/internals/NokogiriNamespaceCache.java +186 -143
  48. data/ext/java/nokogiri/internals/NokogiriNamespaceContext.java +81 -59
  49. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java +66 -49
  50. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +86 -69
  51. data/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +44 -29
  52. data/ext/java/nokogiri/internals/NokogiriXPathFunction.java +121 -48
  53. data/ext/java/nokogiri/internals/NokogiriXPathFunctionResolver.java +34 -22
  54. data/ext/java/nokogiri/internals/NokogiriXPathVariableResolver.java +25 -17
  55. data/ext/java/nokogiri/internals/NokogiriXsltErrorListener.java +57 -42
  56. data/ext/java/nokogiri/internals/ParserContext.java +206 -179
  57. data/ext/java/nokogiri/internals/ReaderNode.java +478 -371
  58. data/ext/java/nokogiri/internals/SaveContextVisitor.java +822 -707
  59. data/ext/java/nokogiri/internals/SchemaErrorHandler.java +28 -19
  60. data/ext/java/nokogiri/internals/XalanDTMManagerPatch.java +129 -123
  61. data/ext/java/nokogiri/internals/XmlDeclHandler.java +5 -4
  62. data/ext/java/nokogiri/internals/XmlDomParserContext.java +208 -177
  63. data/ext/java/nokogiri/internals/XmlSaxParser.java +24 -17
  64. data/ext/java/nokogiri/internals/c14n/AttrCompare.java +71 -68
  65. data/ext/java/nokogiri/internals/c14n/C14nHelper.java +137 -118
  66. data/ext/java/nokogiri/internals/c14n/CanonicalFilter.java +27 -21
  67. data/ext/java/nokogiri/internals/c14n/CanonicalizationException.java +74 -61
  68. data/ext/java/nokogiri/internals/c14n/Canonicalizer.java +230 -205
  69. data/ext/java/nokogiri/internals/c14n/Canonicalizer11.java +572 -547
  70. data/ext/java/nokogiri/internals/c14n/Canonicalizer11_OmitComments.java +17 -10
  71. data/ext/java/nokogiri/internals/c14n/Canonicalizer11_WithComments.java +17 -10
  72. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315.java +323 -302
  73. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315Excl.java +232 -219
  74. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315ExclOmitComments.java +22 -15
  75. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315ExclWithComments.java +23 -16
  76. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315OmitComments.java +23 -16
  77. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315WithComments.java +22 -15
  78. data/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java +575 -545
  79. data/ext/java/nokogiri/internals/c14n/CanonicalizerPhysical.java +141 -120
  80. data/ext/java/nokogiri/internals/c14n/CanonicalizerSpi.java +39 -38
  81. data/ext/java/nokogiri/internals/c14n/Constants.java +13 -10
  82. data/ext/java/nokogiri/internals/c14n/ElementProxy.java +279 -247
  83. data/ext/java/nokogiri/internals/c14n/HelperNodeList.java +66 -53
  84. data/ext/java/nokogiri/internals/c14n/IgnoreAllErrorHandler.java +44 -37
  85. data/ext/java/nokogiri/internals/c14n/InclusiveNamespaces.java +135 -120
  86. data/ext/java/nokogiri/internals/c14n/InvalidCanonicalizerException.java +59 -48
  87. data/ext/java/nokogiri/internals/c14n/NameSpaceSymbTable.java +384 -334
  88. data/ext/java/nokogiri/internals/c14n/NodeFilter.java +25 -24
  89. data/ext/java/nokogiri/internals/c14n/UtfHelpper.java +151 -140
  90. data/ext/java/nokogiri/internals/c14n/XMLUtils.java +456 -423
  91. data/ext/java/nokogiri/internals/dom2dtm/DOM2DTM.java +1466 -1500
  92. data/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java +626 -570
  93. data/ext/nokogiri/depend +37 -358
  94. data/ext/nokogiri/extconf.rb +585 -374
  95. data/ext/nokogiri/html_document.c +78 -82
  96. data/ext/nokogiri/html_element_description.c +84 -71
  97. data/ext/nokogiri/html_entity_lookup.c +21 -16
  98. data/ext/nokogiri/html_sax_parser_context.c +69 -66
  99. data/ext/nokogiri/html_sax_push_parser.c +42 -34
  100. data/ext/nokogiri/libxml2_backwards_compat.c +121 -0
  101. data/ext/nokogiri/nokogiri.c +192 -93
  102. data/ext/nokogiri/test_global_handlers.c +40 -0
  103. data/ext/nokogiri/xml_attr.c +15 -15
  104. data/ext/nokogiri/xml_attribute_decl.c +18 -18
  105. data/ext/nokogiri/xml_cdata.c +13 -18
  106. data/ext/nokogiri/xml_comment.c +19 -26
  107. data/ext/nokogiri/xml_document.c +225 -163
  108. data/ext/nokogiri/xml_document_fragment.c +13 -15
  109. data/ext/nokogiri/xml_dtd.c +54 -48
  110. data/ext/nokogiri/xml_element_content.c +30 -27
  111. data/ext/nokogiri/xml_element_decl.c +22 -22
  112. data/ext/nokogiri/xml_encoding_handler.c +17 -11
  113. data/ext/nokogiri/xml_entity_decl.c +32 -30
  114. data/ext/nokogiri/xml_entity_reference.c +16 -18
  115. data/ext/nokogiri/xml_namespace.c +56 -49
  116. data/ext/nokogiri/xml_node.c +338 -286
  117. data/ext/nokogiri/xml_node_set.c +168 -156
  118. data/ext/nokogiri/xml_processing_instruction.c +17 -19
  119. data/ext/nokogiri/xml_reader.c +195 -172
  120. data/ext/nokogiri/xml_relax_ng.c +52 -28
  121. data/ext/nokogiri/xml_sax_parser.c +118 -118
  122. data/ext/nokogiri/xml_sax_parser_context.c +103 -86
  123. data/ext/nokogiri/xml_sax_push_parser.c +36 -27
  124. data/ext/nokogiri/xml_schema.c +111 -34
  125. data/ext/nokogiri/xml_syntax_error.c +42 -21
  126. data/ext/nokogiri/xml_text.c +13 -17
  127. data/ext/nokogiri/xml_xpath_context.c +206 -123
  128. data/ext/nokogiri/xslt_stylesheet.c +158 -161
  129. data/lib/nokogiri.rb +4 -8
  130. data/lib/nokogiri/css/parser.rb +62 -62
  131. data/lib/nokogiri/css/parser.y +2 -2
  132. data/lib/nokogiri/css/parser_extras.rb +38 -36
  133. data/lib/nokogiri/css/xpath_visitor.rb +70 -42
  134. data/lib/nokogiri/extension.rb +26 -0
  135. data/lib/nokogiri/html/document.rb +12 -26
  136. data/lib/nokogiri/html/document_fragment.rb +15 -15
  137. data/lib/nokogiri/nokogiri.jar +0 -0
  138. data/lib/nokogiri/version.rb +2 -148
  139. data/lib/nokogiri/version/constant.rb +5 -0
  140. data/lib/nokogiri/version/info.rb +205 -0
  141. data/lib/nokogiri/xml/builder.rb +2 -2
  142. data/lib/nokogiri/xml/document.rb +48 -18
  143. data/lib/nokogiri/xml/document_fragment.rb +4 -6
  144. data/lib/nokogiri/xml/node.rb +599 -279
  145. data/lib/nokogiri/xml/parse_options.rb +6 -0
  146. data/lib/nokogiri/xml/reader.rb +2 -9
  147. data/lib/nokogiri/xml/relax_ng.rb +6 -2
  148. data/lib/nokogiri/xml/schema.rb +12 -4
  149. data/lib/nokogiri/xml/searchable.rb +24 -16
  150. data/lib/nokogiri/xml/xpath.rb +1 -3
  151. data/lib/nokogiri/xml/xpath/syntax_error.rb +1 -1
  152. metadata +87 -158
  153. data/ext/nokogiri/html_document.h +0 -10
  154. data/ext/nokogiri/html_element_description.h +0 -10
  155. data/ext/nokogiri/html_entity_lookup.h +0 -8
  156. data/ext/nokogiri/html_sax_parser_context.h +0 -11
  157. data/ext/nokogiri/html_sax_push_parser.h +0 -9
  158. data/ext/nokogiri/nokogiri.h +0 -122
  159. data/ext/nokogiri/xml_attr.h +0 -9
  160. data/ext/nokogiri/xml_attribute_decl.h +0 -9
  161. data/ext/nokogiri/xml_cdata.h +0 -9
  162. data/ext/nokogiri/xml_comment.h +0 -9
  163. data/ext/nokogiri/xml_document.h +0 -23
  164. data/ext/nokogiri/xml_document_fragment.h +0 -10
  165. data/ext/nokogiri/xml_dtd.h +0 -10
  166. data/ext/nokogiri/xml_element_content.h +0 -10
  167. data/ext/nokogiri/xml_element_decl.h +0 -9
  168. data/ext/nokogiri/xml_encoding_handler.h +0 -8
  169. data/ext/nokogiri/xml_entity_decl.h +0 -10
  170. data/ext/nokogiri/xml_entity_reference.h +0 -9
  171. data/ext/nokogiri/xml_io.c +0 -61
  172. data/ext/nokogiri/xml_io.h +0 -11
  173. data/ext/nokogiri/xml_libxml2_hacks.c +0 -112
  174. data/ext/nokogiri/xml_libxml2_hacks.h +0 -12
  175. data/ext/nokogiri/xml_namespace.h +0 -14
  176. data/ext/nokogiri/xml_node.h +0 -13
  177. data/ext/nokogiri/xml_node_set.h +0 -12
  178. data/ext/nokogiri/xml_processing_instruction.h +0 -9
  179. data/ext/nokogiri/xml_reader.h +0 -10
  180. data/ext/nokogiri/xml_relax_ng.h +0 -9
  181. data/ext/nokogiri/xml_sax_parser.h +0 -39
  182. data/ext/nokogiri/xml_sax_parser_context.h +0 -10
  183. data/ext/nokogiri/xml_sax_push_parser.h +0 -9
  184. data/ext/nokogiri/xml_schema.h +0 -9
  185. data/ext/nokogiri/xml_syntax_error.h +0 -13
  186. data/ext/nokogiri/xml_text.h +0 -9
  187. data/ext/nokogiri/xml_xpath_context.h +0 -10
  188. data/ext/nokogiri/xslt_stylesheet.h +0 -14
@@ -17,10 +17,10 @@
17
17
  * distribute, sublicense, and/or sell copies of the Software, and to
18
18
  * permit persons to whom the Software is furnished to do so, subject to
19
19
  * the following conditions:
20
- *
20
+ *
21
21
  * The above copyright notice and this permission notice shall be
22
22
  * included in all copies or substantial portions of the Software.
23
- *
23
+ *
24
24
  * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
25
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
26
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -51,47 +51,58 @@ import org.w3c.dom.Node;
51
51
  * @author Yoko Harada <yokolet@gmail.com>
52
52
  */
53
53
 
54
- @JRubyClass(name="Nokogiri::XML::Comment", parent="Nokogiri::XML::CharacterData")
55
- public class XmlComment extends XmlNode {
56
- public XmlComment(Ruby ruby, RubyClass rubyClass, Node node) {
57
- super(ruby, rubyClass, node);
58
- }
54
+ @JRubyClass(name = "Nokogiri::XML::Comment", parent = "Nokogiri::XML::CharacterData")
55
+ public class XmlComment extends XmlNode
56
+ {
57
+ public
58
+ XmlComment(Ruby ruby, RubyClass rubyClass, Node node)
59
+ {
60
+ super(ruby, rubyClass, node);
61
+ }
59
62
 
60
- public XmlComment(Ruby runtime, RubyClass klass) {
61
- super(runtime, klass);
63
+ public
64
+ XmlComment(Ruby runtime, RubyClass klass)
65
+ {
66
+ super(runtime, klass);
67
+ }
68
+
69
+ @Override
70
+ protected void
71
+ init(ThreadContext context, IRubyObject[] args)
72
+ {
73
+ if (args.length < 2) {
74
+ throw getRuntime().newArgumentError(args.length, 2);
62
75
  }
63
76
 
64
- @Override
65
- protected void init(ThreadContext context, IRubyObject[] args) {
66
- if (args.length < 2)
67
- throw getRuntime().newArgumentError(args.length, 2);
77
+ IRubyObject doc = args[0];
78
+ IRubyObject text = args[1];
68
79
 
69
- IRubyObject doc = args[0];
70
- IRubyObject text = args[1];
80
+ XmlDocument xmlDoc;
81
+ if (doc instanceof XmlDocument) {
82
+ xmlDoc = (XmlDocument) doc;
71
83
 
72
- XmlDocument xmlDoc;
73
- if (doc instanceof XmlDocument) {
74
- xmlDoc = (XmlDocument) doc;
75
-
76
- } else if (doc instanceof XmlNode) {
77
- XmlNode xmlNode = (XmlNode) doc;
78
- xmlDoc = (XmlDocument)xmlNode.document(context);
79
- } else {
80
- throw getRuntime().newArgumentError("first argument must be a XML::Document or XML::Node");
81
- }
82
- if (xmlDoc != null) {
83
- Document document = xmlDoc.getDocument();
84
- Node node = document.createComment(rubyStringToString(text));
85
- setNode(context.runtime, node);
86
- }
84
+ } else if (doc instanceof XmlNode) {
85
+ XmlNode xmlNode = (XmlNode) doc;
86
+ xmlDoc = (XmlDocument)xmlNode.document(context);
87
+ } else {
88
+ throw getRuntime().newArgumentError("first argument must be a XML::Document or XML::Node");
89
+ }
90
+ if (xmlDoc != null) {
91
+ Document document = xmlDoc.getDocument();
92
+ Node node = document.createComment(rubyStringToString(text));
93
+ setNode(context.runtime, node);
87
94
  }
95
+ }
88
96
 
89
- @Override
90
- public boolean isComment() { return true; }
97
+ @Override
98
+ public boolean
99
+ isComment() { return true; }
91
100
 
92
- @Override
93
- public void accept(ThreadContext context, SaveContextVisitor visitor) {
94
- visitor.enter((Comment)node);
95
- visitor.leave((Comment)node);
96
- }
101
+ @Override
102
+ public void
103
+ accept(ThreadContext context, SaveContextVisitor visitor)
104
+ {
105
+ visitor.enter((Comment)node);
106
+ visitor.leave((Comment)node);
107
+ }
97
108
  }
@@ -84,550 +84,652 @@ import nokogiri.internals.c14n.Canonicalizer;
84
84
  * @author John Shahid <jvshahid@gmail.com>
85
85
  */
86
86
 
87
- @JRubyClass(name="Nokogiri::XML::Document", parent="Nokogiri::XML::Node")
88
- public class XmlDocument extends XmlNode {
89
- private NokogiriNamespaceCache nsCache;
90
-
91
- /* UserData keys for storing extra info in the document node. */
92
- public final static String DTD_RAW_DOCUMENT = "DTD_RAW_DOCUMENT";
93
- public final static String DTD_INTERNAL_SUBSET = "DTD_INTERNAL_SUBSET";
94
- public final static String DTD_EXTERNAL_SUBSET = "DTD_EXTERNAL_SUBSET";
95
-
96
- /* DocumentBuilderFactory implementation class name. This needs to set a classloader into it.
97
- * Setting an appropriate classloader resolves issue 380.
98
- */
99
- private static final String DOCUMENTBUILDERFACTORY_IMPLE_NAME = "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl";
100
-
101
- private static final ByteList DOCUMENT = ByteList.create("document");
102
- static { DOCUMENT.setEncoding(USASCIIEncoding.INSTANCE); }
103
-
104
- private static boolean substituteEntities = false;
105
- private static boolean loadExternalSubset = false; // TODO: Verify this.
106
-
107
- /** cache variables */
108
- protected IRubyObject encoding;
109
- protected IRubyObject url;
110
-
111
- public XmlDocument(Ruby runtime, RubyClass klazz) {
112
- super(runtime, klazz, createNewDocument(runtime));
113
- }
114
-
115
- public XmlDocument(Ruby runtime, Document document) {
116
- this(runtime, getNokogiriClass(runtime, "Nokogiri::XML::Document"), document);
117
- }
118
-
119
- public XmlDocument(Ruby runtime, RubyClass klass, Document document) {
120
- super(runtime, klass, document);
121
- init(runtime, document);
122
- }
123
-
124
- void init(Ruby runtime, Document document) {
125
- stabilizeTextContent(document);
126
- if (document.getDocumentElement() != null) {
127
- createAndCacheNamespaces(runtime, document.getDocumentElement());
128
- }
129
- setInstanceVariable("@decorators", runtime.getNil());
130
- }
131
-
132
- public final void setDocumentNode(Ruby runtime, Document node) {
133
- super.setNode(runtime, node);
134
- if (node != null) init(runtime, node);
135
- else setInstanceVariable("@decorators", runtime.getNil());
136
- }
137
-
138
- public void setEncoding(IRubyObject encoding) {
139
- this.encoding = encoding;
140
- }
141
-
142
- public IRubyObject getEncoding() {
143
- return encoding;
144
- }
145
-
146
- // not sure, but like attribute values, text value will be lost
147
- // unless it is referred once before this document is used.
148
- // this seems to happen only when the fragment is parsed from Node#in_context.
149
- protected static void stabilizeTextContent(Document document) {
150
- if (document.getDocumentElement() != null) document.getDocumentElement().getTextContent();
151
- }
152
-
153
- private static void createAndCacheNamespaces(Ruby runtime, Node node) {
154
- if (node.hasAttributes()) {
155
- NamedNodeMap nodeMap = node.getAttributes();
156
- for (int i=0; i<nodeMap.getLength(); i++) {
157
- Node n = nodeMap.item(i);
158
- if (n instanceof Attr) {
159
- Attr attr = (Attr) n;
160
- stabilizeAttr(attr);
161
- if (isNamespace(attr.getName())) {
162
- // create and cache
163
- XmlNamespace.createFromAttr(runtime, attr);
164
- }
165
- }
166
- }
167
- }
168
- NodeList children = node.getChildNodes();
169
- for (int i=0; i<children.getLength(); i++) {
170
- createAndCacheNamespaces(runtime, children.item(i));
171
- }
172
- }
173
-
174
- static void stabilizeAttr(final Attr attr) {
175
- // TODO not sure, but need to get value always before document is referred or lose attribute value
176
- attr.getValue(); // don't delete this line
177
- }
178
-
179
- // When a document is created from fragment with a context (reference) document,
180
- // namespace should be resolved based on the context document.
181
- public XmlDocument(Ruby ruby, RubyClass klass, Document document, XmlDocument contextDoc) {
182
- super(ruby, klass, document);
183
- nsCache = contextDoc.getNamespaceCache();
184
- String default_href = nsCache.getDefault().getHref();
185
- resolveNamespaceIfNecessary(document.getDocumentElement(), default_href);
186
- }
187
-
188
- private void resolveNamespaceIfNecessary(Node node, String default_href) {
189
- if (node == null) return;
190
- String nodePrefix = node.getPrefix();
191
- if (nodePrefix == null) { // default namespace
192
- NokogiriHelpers.renameNode(node, default_href, node.getNodeName());
193
- } else {
194
- String href = getNamespaceCache().get(node, nodePrefix).getHref();
195
- NokogiriHelpers.renameNode(node, href, node.getNodeName());
196
- }
197
- resolveNamespaceIfNecessary(node.getNextSibling(), default_href);
198
- NodeList children = node.getChildNodes();
199
- for (int i=0; i<children.getLength(); i++) {
200
- resolveNamespaceIfNecessary(children.item(i), default_href);
201
- }
202
- }
203
-
204
- public NokogiriNamespaceCache getNamespaceCache() {
205
- if (nsCache == null) nsCache = new NokogiriNamespaceCache();
206
- return nsCache;
207
- }
208
-
209
- public Document getDocument() {
210
- return (Document) node;
211
- }
212
-
213
- @Override
214
- protected IRubyObject getNodeName(ThreadContext context) {
215
- if (name == null) name = RubyString.newStringShared(context.runtime, DOCUMENT);
216
- return name;
217
- }
218
-
219
- public void setUrl(IRubyObject url) {
220
- this.url = url;
221
- }
222
-
223
- protected IRubyObject getUrl() {
224
- return this.url;
225
- }
226
-
227
- @JRubyMethod
228
- public IRubyObject url(ThreadContext context) {
229
- return getUrl();
230
- }
231
-
232
- public static Document createNewDocument(final Ruby runtime) {
233
- try {
234
- return DocumentBuilderFactoryHolder.INSTANCE.newDocumentBuilder().newDocument();
235
- } catch (ParserConfigurationException e) {
236
- throw asRuntimeError(runtime, null, e);
237
- }
238
- }
239
-
240
- private static class DocumentBuilderFactoryHolder {
241
- static final DocumentBuilderFactory INSTANCE;
242
- static {
243
- INSTANCE = DocumentBuilderFactory.newInstance(DOCUMENTBUILDERFACTORY_IMPLE_NAME, NokogiriService.class.getClassLoader());
244
- }
245
- }
246
-
247
- static RaiseException asRuntimeError(Ruby runtime, String message, Exception cause) {
248
- if (cause instanceof RaiseException) return (RaiseException) cause;
249
-
250
- if (message == null) message = cause.toString();
251
- else message = message + '(' + cause.toString() + ')';
252
- RaiseException ex = runtime.newRuntimeError(message);
253
- ex.initCause(cause);
254
- return ex;
255
- }
256
-
257
- /*
258
- * call-seq:
259
- * new(version = default)
260
- *
261
- * Create a new document with +version+ (defaults to "1.0")
262
- */
263
- @JRubyMethod(name="new", meta = true, rest = true, required=0)
264
- public static IRubyObject rbNew(ThreadContext context, IRubyObject klazz, IRubyObject[] args) {
265
- final Ruby runtime = context.runtime;
266
- XmlDocument xmlDocument;
267
- try {
268
- Document docNode = createNewDocument(runtime);
269
- if ("Nokogiri::HTML::Document".equals(((RubyClass)klazz).getName())) {
270
- xmlDocument = new HtmlDocument(context.runtime, (RubyClass) klazz, docNode);
271
- } else {
272
- xmlDocument = new XmlDocument(context.runtime, (RubyClass) klazz, docNode);
273
- }
274
- } catch (Exception ex) {
275
- throw asRuntimeError(runtime, "couldn't create document: ", ex);
276
- }
277
-
278
- Helpers.invoke(context, xmlDocument, "initialize", args);
279
-
280
- return xmlDocument;
281
- }
282
-
283
- @JRubyMethod(required=1, optional=4)
284
- public IRubyObject create_entity(ThreadContext context, IRubyObject[] argv) {
285
- // FIXME: Entity node should be create by some right way.
286
- // this impl passes tests, but entity doesn't exists in DTD, which
287
- // would cause validation failure.
288
- if (argv.length == 0) throw context.runtime.newRuntimeError("Could not create entity");
289
- String tagName = rubyStringToString(argv[0]);
290
- Node node = getOwnerDocument().createElement(tagName);
291
- return XmlEntityDecl.create(context, node, argv);
292
- }
293
-
294
- @Override
295
- XmlDocument document(Ruby runtime) {
296
- return this;
297
- }
298
-
299
- @JRubyMethod(name="encoding=")
300
- public IRubyObject encoding_set(IRubyObject encoding) {
301
- this.encoding = encoding;
302
- return this;
303
- }
304
-
305
- @JRubyMethod
306
- public IRubyObject encoding(ThreadContext context) {
307
- if (this.encoding == null || this.encoding.isNil()) {
308
- final String enc = getDocument().getXmlEncoding();
309
- if (enc == null) {
310
- this.encoding = context.nil;
311
- } else {
312
- this.encoding = context.runtime.newString(enc);
313
- }
87
+ @JRubyClass(name = "Nokogiri::XML::Document", parent = "Nokogiri::XML::Node")
88
+ public class XmlDocument extends XmlNode
89
+ {
90
+ private NokogiriNamespaceCache nsCache;
91
+
92
+ /* UserData keys for storing extra info in the document node. */
93
+ public final static String DTD_RAW_DOCUMENT = "DTD_RAW_DOCUMENT";
94
+ public final static String DTD_INTERNAL_SUBSET = "DTD_INTERNAL_SUBSET";
95
+ public final static String DTD_EXTERNAL_SUBSET = "DTD_EXTERNAL_SUBSET";
96
+
97
+ /* DocumentBuilderFactory implementation class name. This needs to set a classloader into it.
98
+ * Setting an appropriate classloader resolves issue 380.
99
+ */
100
+ private static final String DOCUMENTBUILDERFACTORY_IMPLE_NAME = "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl";
101
+
102
+ private static final ByteList DOCUMENT = ByteList.create("document");
103
+ static { DOCUMENT.setEncoding(USASCIIEncoding.INSTANCE); }
104
+
105
+ private static boolean substituteEntities = false;
106
+ private static boolean loadExternalSubset = false; // TODO: Verify this.
107
+
108
+ /** cache variables */
109
+ protected IRubyObject encoding;
110
+ protected IRubyObject url;
111
+
112
+ public
113
+ XmlDocument(Ruby runtime, RubyClass klazz)
114
+ {
115
+ super(runtime, klazz, createNewDocument(runtime));
116
+ }
117
+
118
+ public
119
+ XmlDocument(Ruby runtime, Document document)
120
+ {
121
+ this(runtime, getNokogiriClass(runtime, "Nokogiri::XML::Document"), document);
122
+ }
123
+
124
+ public
125
+ XmlDocument(Ruby runtime, RubyClass klass, Document document)
126
+ {
127
+ super(runtime, klass, document);
128
+ init(runtime, document);
129
+ }
130
+
131
+ void
132
+ init(Ruby runtime, Document document)
133
+ {
134
+ stabilizeTextContent(document);
135
+ if (document.getDocumentElement() != null) {
136
+ createAndCacheNamespaces(runtime, document.getDocumentElement());
137
+ }
138
+ setInstanceVariable("@decorators", runtime.getNil());
139
+ }
140
+
141
+ public final void
142
+ setDocumentNode(Ruby runtime, Document node)
143
+ {
144
+ super.setNode(runtime, node);
145
+ if (node != null) { init(runtime, node); }
146
+ else { setInstanceVariable("@decorators", runtime.getNil()); }
147
+ }
148
+
149
+ public void
150
+ setEncoding(IRubyObject encoding)
151
+ {
152
+ this.encoding = encoding;
153
+ }
154
+
155
+ public IRubyObject
156
+ getEncoding()
157
+ {
158
+ return encoding;
159
+ }
160
+
161
+ // not sure, but like attribute values, text value will be lost
162
+ // unless it is referred once before this document is used.
163
+ // this seems to happen only when the fragment is parsed from Node#in_context.
164
+ protected static void
165
+ stabilizeTextContent(Document document)
166
+ {
167
+ if (document.getDocumentElement() != null) { document.getDocumentElement().getTextContent(); }
168
+ }
169
+
170
+ private static void
171
+ createAndCacheNamespaces(Ruby runtime, Node node)
172
+ {
173
+ if (node.hasAttributes()) {
174
+ NamedNodeMap nodeMap = node.getAttributes();
175
+ for (int i = 0; i < nodeMap.getLength(); i++) {
176
+ Node n = nodeMap.item(i);
177
+ if (n instanceof Attr) {
178
+ Attr attr = (Attr) n;
179
+ stabilizeAttr(attr);
180
+ if (isNamespace(attr.getName())) {
181
+ // create and cache
182
+ XmlNamespace.createFromAttr(runtime, attr);
183
+ }
314
184
  }
315
-
316
- return this.encoding.isNil() ? this.encoding : this.encoding.asString().encode(context, context.getRuntime().newString("UTF-8"));
317
- }
318
-
319
- @JRubyMethod(meta = true)
320
- public static IRubyObject load_external_subsets_set(ThreadContext context, IRubyObject cls, IRubyObject value) {
321
- XmlDocument.loadExternalSubset = value.isTrue();
322
- return context.nil;
323
- }
324
-
325
- @JRubyMethod(meta = true, required = 4)
326
- public static IRubyObject read_io(ThreadContext context, IRubyObject klass, IRubyObject[] args) {
327
- XmlDomParserContext ctx = new XmlDomParserContext(context.runtime, args[2], args[3]);
328
- ctx.setIOInputSource(context, args[0], args[1]);
329
- return ctx.parse(context, (RubyClass) klass, args[1]);
330
- }
331
-
332
- @JRubyMethod(meta = true, required = 4)
333
- public static IRubyObject read_memory(ThreadContext context, IRubyObject klass, IRubyObject[] args) {
334
- XmlDomParserContext ctx = new XmlDomParserContext(context.runtime, args[2], args[3]);
335
- ctx.setStringInputSource(context, args[0], args[1]);
336
- return ctx.parse(context, (RubyClass) klass, args[1]);
337
- }
338
-
339
- @JRubyMethod(name="remove_namespaces!")
340
- public IRubyObject remove_namespaces(ThreadContext context) {
341
- removeNamespaceRecursively(this);
342
- if (nsCache != null) nsCache.clear();
343
- clearXpathContext(getNode());
344
- return this;
345
- }
346
-
347
- private void removeNamespaceRecursively(XmlNode xmlNode) {
348
- Node node = xmlNode.node;
349
- if (node.getNodeType() == Node.ELEMENT_NODE) {
350
- node.setPrefix(null);
351
- NokogiriHelpers.renameNode(node, null, node.getLocalName());
352
- NamedNodeMap attrs = node.getAttributes();
353
- for (int i=0; i<attrs.getLength(); i++) {
354
- Attr attr = (Attr) attrs.item(i);
355
- if (isNamespace(attr.getNodeName())) {
356
- ((org.w3c.dom.Element) node).removeAttributeNode(attr);
357
- } else {
358
- attr.setPrefix(null);
359
- NokogiriHelpers.renameNode(attr, null, attr.getLocalName());
360
- }
361
- }
362
- }
363
- IRubyObject[] nodes = xmlNode.getChildren();
364
- for (int i=0; i < nodes.length; i++) {
365
- XmlNode childNode = (XmlNode) nodes[i];
366
- removeNamespaceRecursively(childNode);
367
- }
368
- }
369
-
370
- @JRubyMethod
371
- public IRubyObject root(ThreadContext context) {
372
- Node rootNode = getDocument().getDocumentElement();
373
- if (rootNode == null) return context.nil;
374
-
375
- Object invalid = rootNode.getUserData(NokogiriHelpers.ROOT_NODE_INVALID);
376
- if (invalid != null && ((Boolean) invalid)) return context.nil;
377
-
378
- return getCachedNodeOrCreate(context.runtime, rootNode);
379
- }
380
-
381
- protected IRubyObject dup_implementation(Ruby runtime, boolean deep) {
382
- XmlDocument doc = (XmlDocument) super.dup_implementation(runtime, deep);
383
- // Avoid creating a new XmlDocument since we cloned one
384
- // already. Otherwise the following test will fail:
385
- //
386
- // dup = doc.dup
387
- // dup.equal?(dup.children[0].document)
388
- //
389
- // Since `dup.children[0].document' will end up creating a new
390
- // XmlDocument. See #1060.
391
- doc.resetCache();
392
- return doc;
393
- }
394
-
395
- @JRubyMethod(name="root=")
396
- public IRubyObject root_set(ThreadContext context, IRubyObject new_root) {
397
- // in case of document fragment, temporary root node should be deleted.
398
-
399
- // Java can't have a root whose value is null. Instead of setting null,
400
- // the method sets user data so that other methods are able to know the root
401
- // should be nil.
402
- if (new_root == context.nil) {
403
- getDocument().getDocumentElement().setUserData(NokogiriHelpers.ROOT_NODE_INVALID, Boolean.TRUE, null);
404
- return new_root;
405
- }
406
- XmlNode newRoot = asXmlNode(context, new_root);
407
-
408
- IRubyObject root = root(context);
409
- if (root.isNil()) {
410
- Node newRootNode;
411
- if (getDocument() == newRoot.getOwnerDocument()) {
412
- newRootNode = newRoot.node;
413
- } else {
414
- // must copy otherwise newRoot may exist in two places
415
- // with different owner document.
416
- newRootNode = getDocument().importNode(newRoot.node, true);
417
- }
418
- add_child_node(context, getCachedNodeOrCreate(context.runtime, newRootNode));
185
+ }
186
+ }
187
+ NodeList children = node.getChildNodes();
188
+ for (int i = 0; i < children.getLength(); i++) {
189
+ createAndCacheNamespaces(runtime, children.item(i));
190
+ }
191
+ }
192
+
193
+ static void
194
+ stabilizeAttr(final Attr attr)
195
+ {
196
+ // TODO not sure, but need to get value always before document is referred or lose attribute value
197
+ attr.getValue(); // don't delete this line
198
+ }
199
+
200
+ // When a document is created from fragment with a context (reference) document,
201
+ // namespace should be resolved based on the context document.
202
+ public
203
+ XmlDocument(Ruby ruby, RubyClass klass, Document document, XmlDocument contextDoc)
204
+ {
205
+ super(ruby, klass, document);
206
+ nsCache = contextDoc.getNamespaceCache();
207
+ String default_href = nsCache.getDefault().getHref();
208
+ resolveNamespaceIfNecessary(document.getDocumentElement(), default_href);
209
+ }
210
+
211
+ private void
212
+ resolveNamespaceIfNecessary(Node node, String default_href)
213
+ {
214
+ if (node == null) { return; }
215
+ String nodePrefix = node.getPrefix();
216
+ if (nodePrefix == null) { // default namespace
217
+ NokogiriHelpers.renameNode(node, default_href, node.getNodeName());
218
+ } else {
219
+ String href = getNamespaceCache().get(node, nodePrefix).getHref();
220
+ NokogiriHelpers.renameNode(node, href, node.getNodeName());
221
+ }
222
+ resolveNamespaceIfNecessary(node.getNextSibling(), default_href);
223
+ NodeList children = node.getChildNodes();
224
+ for (int i = 0; i < children.getLength(); i++) {
225
+ resolveNamespaceIfNecessary(children.item(i), default_href);
226
+ }
227
+ }
228
+
229
+ public NokogiriNamespaceCache
230
+ getNamespaceCache()
231
+ {
232
+ if (nsCache == null) { nsCache = new NokogiriNamespaceCache(); }
233
+ return nsCache;
234
+ }
235
+
236
+ public Document
237
+ getDocument()
238
+ {
239
+ return (Document) node;
240
+ }
241
+
242
+ @Override
243
+ protected IRubyObject
244
+ getNodeName(ThreadContext context)
245
+ {
246
+ if (name == null) { name = RubyString.newStringShared(context.runtime, DOCUMENT); }
247
+ return name;
248
+ }
249
+
250
+ public void
251
+ setUrl(IRubyObject url)
252
+ {
253
+ this.url = url;
254
+ }
255
+
256
+ protected IRubyObject
257
+ getUrl()
258
+ {
259
+ return this.url;
260
+ }
261
+
262
+ @JRubyMethod
263
+ public IRubyObject
264
+ url(ThreadContext context)
265
+ {
266
+ return getUrl();
267
+ }
268
+
269
+ public static Document
270
+ createNewDocument(final Ruby runtime)
271
+ {
272
+ try {
273
+ return DocumentBuilderFactoryHolder.INSTANCE.newDocumentBuilder().newDocument();
274
+ } catch (ParserConfigurationException e) {
275
+ throw asRuntimeError(runtime, null, e);
276
+ }
277
+ }
278
+
279
+ private static class DocumentBuilderFactoryHolder
280
+ {
281
+ static final DocumentBuilderFactory INSTANCE;
282
+ static
283
+ {
284
+ INSTANCE = DocumentBuilderFactory.newInstance(DOCUMENTBUILDERFACTORY_IMPLE_NAME,
285
+ NokogiriService.class.getClassLoader());
286
+ }
287
+ }
288
+
289
+ static RaiseException
290
+ asRuntimeError(Ruby runtime, String message, Exception cause)
291
+ {
292
+ if (cause instanceof RaiseException) { return (RaiseException) cause; }
293
+
294
+ if (message == null) { message = cause.toString(); }
295
+ else { message = message + '(' + cause.toString() + ')'; }
296
+ RaiseException ex = runtime.newRuntimeError(message);
297
+ ex.initCause(cause);
298
+ return ex;
299
+ }
300
+
301
+ /*
302
+ * call-seq:
303
+ * new(version = default)
304
+ *
305
+ * Create a new document with +version+ (defaults to "1.0")
306
+ */
307
+ @JRubyMethod(name = "new", meta = true, rest = true, required = 0)
308
+ public static IRubyObject
309
+ rbNew(ThreadContext context, IRubyObject klazz, IRubyObject[] args)
310
+ {
311
+ final Ruby runtime = context.runtime;
312
+ XmlDocument xmlDocument;
313
+ try {
314
+ Document docNode = createNewDocument(runtime);
315
+ if ("Nokogiri::HTML::Document".equals(((RubyClass)klazz).getName())) {
316
+ xmlDocument = new HtmlDocument(context.runtime, (RubyClass) klazz, docNode);
317
+ } else {
318
+ xmlDocument = new XmlDocument(context.runtime, (RubyClass) klazz, docNode);
319
+ }
320
+ } catch (Exception ex) {
321
+ throw asRuntimeError(runtime, "couldn't create document: ", ex);
322
+ }
323
+
324
+ Helpers.invoke(context, xmlDocument, "initialize", args);
325
+
326
+ return xmlDocument;
327
+ }
328
+
329
+ @JRubyMethod(required = 1, optional = 4)
330
+ public IRubyObject
331
+ create_entity(ThreadContext context, IRubyObject[] argv)
332
+ {
333
+ // FIXME: Entity node should be create by some right way.
334
+ // this impl passes tests, but entity doesn't exists in DTD, which
335
+ // would cause validation failure.
336
+ if (argv.length == 0) { throw context.runtime.newRuntimeError("Could not create entity"); }
337
+ String tagName = rubyStringToString(argv[0]);
338
+ Node node = getOwnerDocument().createElement(tagName);
339
+ return XmlEntityDecl.create(context, node, argv);
340
+ }
341
+
342
+ @Override
343
+ XmlDocument
344
+ document(Ruby runtime)
345
+ {
346
+ return this;
347
+ }
348
+
349
+ @JRubyMethod(name = "encoding=")
350
+ public IRubyObject
351
+ encoding_set(IRubyObject encoding)
352
+ {
353
+ this.encoding = encoding;
354
+ return this;
355
+ }
356
+
357
+ @JRubyMethod
358
+ public IRubyObject
359
+ encoding(ThreadContext context)
360
+ {
361
+ if (this.encoding == null || this.encoding.isNil()) {
362
+ final String enc = getDocument().getXmlEncoding();
363
+ if (enc == null) {
364
+ this.encoding = context.nil;
365
+ } else {
366
+ this.encoding = context.runtime.newString(enc);
367
+ }
368
+ }
369
+
370
+ return this.encoding.isNil() ? this.encoding : this.encoding.asString().encode(context,
371
+ context.getRuntime().newString("UTF-8"));
372
+ }
373
+
374
+ @JRubyMethod(meta = true)
375
+ public static IRubyObject
376
+ load_external_subsets_set(ThreadContext context, IRubyObject cls, IRubyObject value)
377
+ {
378
+ XmlDocument.loadExternalSubset = value.isTrue();
379
+ return context.nil;
380
+ }
381
+
382
+ @JRubyMethod(meta = true, required = 4)
383
+ public static IRubyObject
384
+ read_io(ThreadContext context, IRubyObject klass, IRubyObject[] args)
385
+ {
386
+ XmlDomParserContext ctx = new XmlDomParserContext(context.runtime, args[2], args[3]);
387
+ ctx.setIOInputSource(context, args[0], args[1]);
388
+ return ctx.parse(context, (RubyClass) klass, args[1]);
389
+ }
390
+
391
+ @JRubyMethod(meta = true, required = 4)
392
+ public static IRubyObject
393
+ read_memory(ThreadContext context, IRubyObject klass, IRubyObject[] args)
394
+ {
395
+ XmlDomParserContext ctx = new XmlDomParserContext(context.runtime, args[2], args[3]);
396
+ ctx.setStringInputSource(context, args[0], args[1]);
397
+ return ctx.parse(context, (RubyClass) klass, args[1]);
398
+ }
399
+
400
+ @JRubyMethod(name = "remove_namespaces!")
401
+ public IRubyObject
402
+ remove_namespaces(ThreadContext context)
403
+ {
404
+ removeNamespaceRecursively(this);
405
+ if (nsCache != null) { nsCache.clear(); }
406
+ clearXpathContext(getNode());
407
+ return this;
408
+ }
409
+
410
+ private void
411
+ removeNamespaceRecursively(XmlNode xmlNode)
412
+ {
413
+ Node node = xmlNode.node;
414
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
415
+ node.setPrefix(null);
416
+ NokogiriHelpers.renameNode(node, null, node.getLocalName());
417
+ NamedNodeMap attrs = node.getAttributes();
418
+ for (int i = 0; i < attrs.getLength(); i++) {
419
+ Attr attr = (Attr) attrs.item(i);
420
+ if (isNamespace(attr.getNodeName())) {
421
+ ((org.w3c.dom.Element) node).removeAttributeNode(attr);
419
422
  } else {
420
- Node rootNode = asXmlNode(context, root).node;
421
- ((XmlNode) getCachedNodeOrCreate(context.runtime, rootNode)).replace_node(context, newRoot);
423
+ attr.setPrefix(null);
424
+ NokogiriHelpers.renameNode(attr, null, attr.getLocalName());
422
425
  }
423
-
424
- return newRoot;
425
- }
426
-
427
- @JRubyMethod
428
- public IRubyObject version(ThreadContext context) {
429
- return stringOrNil(context.runtime, getDocument().getXmlVersion());
430
- }
431
-
432
- @JRubyMethod(meta = true)
433
- public static IRubyObject substitute_entities_set(ThreadContext context, IRubyObject cls, IRubyObject value) {
434
- XmlDocument.substituteEntities = value.isTrue();
435
- return context.nil;
436
- }
437
-
438
- public IRubyObject getInternalSubset(ThreadContext context) {
439
- IRubyObject dtd = (IRubyObject) node.getUserData(DTD_INTERNAL_SUBSET);
440
-
441
- if (dtd == null) {
442
- Document document = getDocument();
443
- if (document.getUserData(XmlDocument.DTD_RAW_DOCUMENT) != null) {
444
- dtd = XmlDtd.newFromInternalSubset(context.runtime, document);
445
- } else if (document.getDoctype() != null) {
446
- DocumentType docType = document.getDoctype();
447
- IRubyObject name, publicId, systemId;
448
- name = publicId = systemId = context.nil;
449
- if (docType.getName() != null) {
450
- name = context.runtime.newString(docType.getName());
451
- }
452
- if (docType.getPublicId() != null) {
453
- publicId = context.runtime.newString(docType.getPublicId());
454
- }
455
- if (docType.getSystemId() != null) {
456
- systemId = context.runtime.newString(docType.getSystemId());
457
- }
458
- dtd = XmlDtd.newEmpty(context.runtime, document, name, publicId, systemId);
459
- } else {
460
- dtd = context.nil;
461
- }
462
-
463
- setInternalSubset(dtd);
426
+ }
427
+ }
428
+ IRubyObject[] nodes = xmlNode.getChildren();
429
+ for (int i = 0; i < nodes.length; i++) {
430
+ XmlNode childNode = (XmlNode) nodes[i];
431
+ removeNamespaceRecursively(childNode);
432
+ }
433
+ }
434
+
435
+ @JRubyMethod
436
+ public IRubyObject
437
+ root(ThreadContext context)
438
+ {
439
+ Node rootNode = getDocument().getDocumentElement();
440
+ if (rootNode == null) { return context.nil; }
441
+
442
+ Object invalid = rootNode.getUserData(NokogiriHelpers.ROOT_NODE_INVALID);
443
+ if (invalid != null && ((Boolean) invalid)) { return context.nil; }
444
+
445
+ return getCachedNodeOrCreate(context.runtime, rootNode);
446
+ }
447
+
448
+ protected IRubyObject
449
+ dup_implementation(Ruby runtime, boolean deep)
450
+ {
451
+ XmlDocument doc = (XmlDocument) super.dup_implementation(runtime, deep);
452
+ // Avoid creating a new XmlDocument since we cloned one
453
+ // already. Otherwise the following test will fail:
454
+ //
455
+ // dup = doc.dup
456
+ // dup.equal?(dup.children[0].document)
457
+ //
458
+ // Since `dup.children[0].document' will end up creating a new
459
+ // XmlDocument. See #1060.
460
+ doc.resetCache();
461
+ return doc;
462
+ }
463
+
464
+ @JRubyMethod(name = "root=")
465
+ public IRubyObject
466
+ root_set(ThreadContext context, IRubyObject new_root)
467
+ {
468
+ // in case of document fragment, temporary root node should be deleted.
469
+
470
+ // Java can't have a root whose value is null. Instead of setting null,
471
+ // the method sets user data so that other methods are able to know the root
472
+ // should be nil.
473
+ if (new_root == context.nil) {
474
+ getDocument().getDocumentElement().setUserData(NokogiriHelpers.ROOT_NODE_INVALID, Boolean.TRUE, null);
475
+ return new_root;
476
+ }
477
+ XmlNode newRoot = asXmlNode(context, new_root);
478
+
479
+ IRubyObject root = root(context);
480
+ if (root.isNil()) {
481
+ Node newRootNode;
482
+ if (getDocument() == newRoot.getOwnerDocument()) {
483
+ newRootNode = newRoot.node;
484
+ } else {
485
+ // must copy otherwise newRoot may exist in two places
486
+ // with different owner document.
487
+ newRootNode = getDocument().importNode(newRoot.node, true);
488
+ }
489
+ add_child_node(context, getCachedNodeOrCreate(context.runtime, newRootNode));
490
+ } else {
491
+ Node rootNode = asXmlNode(context, root).node;
492
+ ((XmlNode) getCachedNodeOrCreate(context.runtime, rootNode)).replace_node(context, newRoot);
493
+ }
494
+
495
+ return newRoot;
496
+ }
497
+
498
+ @JRubyMethod
499
+ public IRubyObject
500
+ version(ThreadContext context)
501
+ {
502
+ return stringOrNil(context.runtime, getDocument().getXmlVersion());
503
+ }
504
+
505
+ @JRubyMethod(meta = true)
506
+ public static IRubyObject
507
+ substitute_entities_set(ThreadContext context, IRubyObject cls, IRubyObject value)
508
+ {
509
+ XmlDocument.substituteEntities = value.isTrue();
510
+ return context.nil;
511
+ }
512
+
513
+ public IRubyObject
514
+ getInternalSubset(ThreadContext context)
515
+ {
516
+ IRubyObject dtd = (IRubyObject) node.getUserData(DTD_INTERNAL_SUBSET);
517
+
518
+ if (dtd == null) {
519
+ Document document = getDocument();
520
+ if (document.getUserData(XmlDocument.DTD_RAW_DOCUMENT) != null) {
521
+ dtd = XmlDtd.newFromInternalSubset(context.runtime, document);
522
+ } else if (document.getDoctype() != null) {
523
+ DocumentType docType = document.getDoctype();
524
+ IRubyObject name, publicId, systemId;
525
+ name = publicId = systemId = context.nil;
526
+ if (docType.getName() != null) {
527
+ name = context.runtime.newString(docType.getName());
464
528
  }
465
-
466
- return dtd;
467
- }
468
-
469
- /**
470
- * Assumes XmlNode#internal_subset() has returned nil. (i.e. there
471
- * is not already an internal subset).
472
- */
473
- public IRubyObject createInternalSubset(ThreadContext context,
474
- IRubyObject name,
475
- IRubyObject external_id,
476
- IRubyObject system_id) {
477
- XmlDtd dtd = XmlDtd.newEmpty(context.runtime, getDocument(), name, external_id, system_id);
478
- setInternalSubset(dtd);
479
- return dtd;
480
- }
481
-
482
- protected void setInternalSubset(IRubyObject data) {
483
- node.setUserData(DTD_INTERNAL_SUBSET, data, null);
484
- }
485
-
486
- public IRubyObject getExternalSubset(ThreadContext context) {
487
- IRubyObject dtd = (IRubyObject) node.getUserData(DTD_EXTERNAL_SUBSET);
488
-
489
- if (dtd == null) return context.nil;
490
- return dtd;
491
- }
492
-
493
- /**
494
- * Assumes XmlNode#external_subset() has returned nil. (i.e. there
495
- * is not already an external subset).
496
- */
497
- public IRubyObject createExternalSubset(ThreadContext context,
498
- IRubyObject name,
499
- IRubyObject external_id,
500
- IRubyObject system_id) {
501
- XmlDtd dtd = XmlDtd.newEmpty(context.runtime, getDocument(), name, external_id, system_id);
502
- setExternalSubset(dtd);
503
- return dtd;
504
- }
505
-
506
- protected void setExternalSubset(IRubyObject data) {
507
- node.setUserData(DTD_EXTERNAL_SUBSET, data, null);
508
- }
509
-
510
- @Override
511
- public void accept(ThreadContext context, SaveContextVisitor visitor) {
512
- Document document = getDocument();
513
- visitor.enter(document);
514
- NodeList children = document.getChildNodes();
515
- for (int i=0; i<children.getLength(); i++) {
516
- Node child = children.item(i);
517
- short type = child.getNodeType();
518
- if (type == Node.COMMENT_NODE) {
519
- XmlComment xmlComment = (XmlComment) getCachedNodeOrCreate(context.runtime, child);
520
- xmlComment.accept(context, visitor);
521
- } else if (type == Node.DOCUMENT_TYPE_NODE) {
522
- XmlDtd xmlDtd = (XmlDtd) getCachedNodeOrCreate(context.runtime, child);
523
- xmlDtd.accept(context, visitor);
524
- } else if (type == Node.PROCESSING_INSTRUCTION_NODE) {
525
- XmlProcessingInstruction xmlProcessingInstruction = (XmlProcessingInstruction) getCachedNodeOrCreate(context.runtime, child);
526
- xmlProcessingInstruction.accept(context, visitor);
527
- } else if (type == Node.TEXT_NODE) {
528
- XmlText xmlText = (XmlText) getCachedNodeOrCreate(context.runtime, child);
529
- xmlText.accept(context, visitor);
530
- } else if (type == Node.ELEMENT_NODE) {
531
- XmlElement xmlElement = (XmlElement) getCachedNodeOrCreate(context.runtime, child);
532
- xmlElement.accept(context, visitor);
533
- }
534
- }
535
- visitor.leave(document);
536
- }
537
-
538
- @JRubyMethod(meta = true)
539
- public static IRubyObject wrap(ThreadContext context, IRubyObject klass, IRubyObject arg) {
540
- XmlDocument xmlDocument = new XmlDocument(context.runtime, (RubyClass) klass, (Document) arg.toJava(Document.class));
541
- Helpers.invoke(context, xmlDocument, "initialize");
542
- return xmlDocument;
543
- }
544
-
545
- @Deprecated
546
- @JRubyMethod(meta = true, visibility = Visibility.PRIVATE)
547
- public static IRubyObject wrapJavaDocument(ThreadContext context, IRubyObject klass, IRubyObject arg) {
548
- return wrap(context, klass, arg);
549
- }
550
-
551
- @Deprecated // default to_java works (due inherited from XmlNode#toJava)
552
- @JRubyMethod(visibility = Visibility.PRIVATE)
553
- public IRubyObject toJavaDocument(ThreadContext context) {
554
- return JavaUtil.convertJavaToUsableRubyObject(context.getRuntime(), node);
555
- }
556
-
557
- /* call-seq:
558
- * doc.canonicalize(mode=XML_C14N_1_0,inclusive_namespaces=nil,with_comments=false)
559
- * doc.canonicalize { |obj, parent| ... }
560
- *
561
- * Canonicalize a document and return the results. Takes an optional block
562
- * that takes two parameters: the +obj+ and that node's +parent+.
563
- * The +obj+ will be either a Nokogiri::XML::Node, or a Nokogiri::XML::Namespace
564
- * The block must return a non-nil, non-false value if the +obj+ passed in
565
- * should be included in the canonicalized document.
566
- */
567
- @JRubyMethod(optional=3)
568
- public IRubyObject canonicalize(ThreadContext context, IRubyObject[] args, Block block) {
569
- int mode = 0;
570
- String inclusive_namespace = null;
571
- Boolean with_comments = false;
572
- if (args.length > 0 && !(args[0].isNil())) {
573
- mode = RubyFixnum.fix2int(args[0]);
574
- }
575
- if (args.length > 1 ) {
576
- if (!args[1].isNil() && !(args[1] instanceof List)) {
577
- throw context.runtime.newTypeError("Expected array");
578
- }
579
- if (!args[1].isNil()) {
580
- inclusive_namespace = ((RubyArray)args[1])
581
- .join(context, context.runtime.newString(" "))
582
- .asString()
583
- .asJavaString(); // OMG I wish I knew JRuby better, this is ugly
584
- }
529
+ if (docType.getPublicId() != null) {
530
+ publicId = context.runtime.newString(docType.getPublicId());
585
531
  }
586
- if (args.length > 2) {
587
- with_comments = args[2].isTrue();
532
+ if (docType.getSystemId() != null) {
533
+ systemId = context.runtime.newString(docType.getSystemId());
588
534
  }
589
- String algorithmURI = null;
590
- switch(mode) {
591
- case 0: // XML_C14N_1_0
592
- if (with_comments) algorithmURI = Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS;
593
- else algorithmURI = Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS;
594
- break;
595
- case 1: // XML_C14N_EXCLUSIVE_1_0
596
- if (with_comments) algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS;
597
- else algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
598
- break;
599
- case 2: // XML_C14N_1_1 = 2
600
- if (with_comments) algorithmURI = Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS;
601
- else algorithmURI = Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS;
602
- }
603
- try {
604
- Canonicalizer canonicalizer = Canonicalizer.getInstance(algorithmURI);
605
- XmlNode startingNode = getStartingNode(block);
606
- byte[] result;
607
- CanonicalFilter filter = new CanonicalFilter(context, block);
608
- if (inclusive_namespace == null) {
609
- result = canonicalizer.canonicalizeSubtree(startingNode.getNode(), filter);
610
- } else {
611
- result = canonicalizer.canonicalizeSubtree(startingNode.getNode(), inclusive_namespace, filter);
612
- }
613
- return RubyString.newString(context.runtime, new ByteList(result, UTF8Encoding.INSTANCE));
614
- } catch (CanonicalizationException e) {
615
- // TODO Auto-generated catch block
616
- e.printStackTrace();
617
- }
618
- return context.nil;
619
- }
620
-
621
- private XmlNode getStartingNode(Block block) {
622
- if (block.isGiven()) {
623
- IRubyObject boundSelf = block.getBinding().getSelf();
624
- if (boundSelf instanceof XmlNode) return (XmlNode) boundSelf;
625
- }
626
- return this;
627
- }
628
-
629
- public void resetNamespaceCache(ThreadContext context) {
630
- nsCache = new NokogiriNamespaceCache();
631
- createAndCacheNamespaces(context.runtime, node);
632
- }
535
+ dtd = XmlDtd.newEmpty(context.runtime, document, name, publicId, systemId);
536
+ } else {
537
+ dtd = context.nil;
538
+ }
539
+
540
+ setInternalSubset(dtd);
541
+ }
542
+
543
+ return dtd;
544
+ }
545
+
546
+ /**
547
+ * Assumes XmlNode#internal_subset() has returned nil. (i.e. there
548
+ * is not already an internal subset).
549
+ */
550
+ public IRubyObject
551
+ createInternalSubset(ThreadContext context,
552
+ IRubyObject name,
553
+ IRubyObject external_id,
554
+ IRubyObject system_id)
555
+ {
556
+ XmlDtd dtd = XmlDtd.newEmpty(context.runtime, getDocument(), name, external_id, system_id);
557
+ setInternalSubset(dtd);
558
+ return dtd;
559
+ }
560
+
561
+ protected void
562
+ setInternalSubset(IRubyObject data)
563
+ {
564
+ node.setUserData(DTD_INTERNAL_SUBSET, data, null);
565
+ }
566
+
567
+ public IRubyObject
568
+ getExternalSubset(ThreadContext context)
569
+ {
570
+ IRubyObject dtd = (IRubyObject) node.getUserData(DTD_EXTERNAL_SUBSET);
571
+
572
+ if (dtd == null) { return context.nil; }
573
+ return dtd;
574
+ }
575
+
576
+ /**
577
+ * Assumes XmlNode#external_subset() has returned nil. (i.e. there
578
+ * is not already an external subset).
579
+ */
580
+ public IRubyObject
581
+ createExternalSubset(ThreadContext context,
582
+ IRubyObject name,
583
+ IRubyObject external_id,
584
+ IRubyObject system_id)
585
+ {
586
+ XmlDtd dtd = XmlDtd.newEmpty(context.runtime, getDocument(), name, external_id, system_id);
587
+ setExternalSubset(dtd);
588
+ return dtd;
589
+ }
590
+
591
+ protected void
592
+ setExternalSubset(IRubyObject data)
593
+ {
594
+ node.setUserData(DTD_EXTERNAL_SUBSET, data, null);
595
+ }
596
+
597
+ @Override
598
+ public void
599
+ accept(ThreadContext context, SaveContextVisitor visitor)
600
+ {
601
+ Document document = getDocument();
602
+ visitor.enter(document);
603
+ NodeList children = document.getChildNodes();
604
+ for (int i = 0; i < children.getLength(); i++) {
605
+ Node child = children.item(i);
606
+ short type = child.getNodeType();
607
+ if (type == Node.COMMENT_NODE) {
608
+ XmlComment xmlComment = (XmlComment) getCachedNodeOrCreate(context.runtime, child);
609
+ xmlComment.accept(context, visitor);
610
+ } else if (type == Node.DOCUMENT_TYPE_NODE) {
611
+ XmlDtd xmlDtd = (XmlDtd) getCachedNodeOrCreate(context.runtime, child);
612
+ xmlDtd.accept(context, visitor);
613
+ } else if (type == Node.PROCESSING_INSTRUCTION_NODE) {
614
+ XmlProcessingInstruction xmlProcessingInstruction = (XmlProcessingInstruction) getCachedNodeOrCreate(context.runtime,
615
+ child);
616
+ xmlProcessingInstruction.accept(context, visitor);
617
+ } else if (type == Node.TEXT_NODE) {
618
+ XmlText xmlText = (XmlText) getCachedNodeOrCreate(context.runtime, child);
619
+ xmlText.accept(context, visitor);
620
+ } else if (type == Node.ELEMENT_NODE) {
621
+ XmlElement xmlElement = (XmlElement) getCachedNodeOrCreate(context.runtime, child);
622
+ xmlElement.accept(context, visitor);
623
+ }
624
+ }
625
+ visitor.leave(document);
626
+ }
627
+
628
+ @JRubyMethod(meta = true)
629
+ public static IRubyObject
630
+ wrap(ThreadContext context, IRubyObject klass, IRubyObject arg)
631
+ {
632
+ XmlDocument xmlDocument = new XmlDocument(context.runtime, (RubyClass) klass, (Document) arg.toJava(Document.class));
633
+ Helpers.invoke(context, xmlDocument, "initialize");
634
+ return xmlDocument;
635
+ }
636
+
637
+ @Deprecated
638
+ @JRubyMethod(meta = true, visibility = Visibility.PRIVATE)
639
+ public static IRubyObject
640
+ wrapJavaDocument(ThreadContext context, IRubyObject klass, IRubyObject arg)
641
+ {
642
+ return wrap(context, klass, arg);
643
+ }
644
+
645
+ @Deprecated // default to_java works (due inherited from XmlNode#toJava)
646
+ @JRubyMethod(visibility = Visibility.PRIVATE)
647
+ public IRubyObject
648
+ toJavaDocument(ThreadContext context)
649
+ {
650
+ return JavaUtil.convertJavaToUsableRubyObject(context.getRuntime(), node);
651
+ }
652
+
653
+ /* call-seq:
654
+ * doc.canonicalize(mode=XML_C14N_1_0,inclusive_namespaces=nil,with_comments=false)
655
+ * doc.canonicalize { |obj, parent| ... }
656
+ *
657
+ * Canonicalize a document and return the results. Takes an optional block
658
+ * that takes two parameters: the +obj+ and that node's +parent+.
659
+ * The +obj+ will be either a Nokogiri::XML::Node, or a Nokogiri::XML::Namespace
660
+ * The block must return a non-nil, non-false value if the +obj+ passed in
661
+ * should be included in the canonicalized document.
662
+ */
663
+ @JRubyMethod(optional = 3)
664
+ public IRubyObject
665
+ canonicalize(ThreadContext context, IRubyObject[] args, Block block)
666
+ {
667
+ int mode = 0;
668
+ String inclusive_namespace = null;
669
+ Boolean with_comments = false;
670
+ if (args.length > 0 && !(args[0].isNil())) {
671
+ mode = RubyFixnum.fix2int(args[0]);
672
+ }
673
+ if (args.length > 1) {
674
+ if (!args[1].isNil() && !(args[1] instanceof List)) {
675
+ throw context.runtime.newTypeError("Expected array");
676
+ }
677
+ if (!args[1].isNil()) {
678
+ inclusive_namespace = ((RubyArray)args[1])
679
+ .join(context, context.runtime.newString(" "))
680
+ .asString()
681
+ .asJavaString(); // OMG I wish I knew JRuby better, this is ugly
682
+ }
683
+ }
684
+ if (args.length > 2) {
685
+ with_comments = args[2].isTrue();
686
+ }
687
+ String algorithmURI = null;
688
+ switch (mode) {
689
+ case 0: // XML_C14N_1_0
690
+ if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS; }
691
+ else { algorithmURI = Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS; }
692
+ break;
693
+ case 1: // XML_C14N_EXCLUSIVE_1_0
694
+ if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS; }
695
+ else { algorithmURI = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS; }
696
+ break;
697
+ case 2: // XML_C14N_1_1 = 2
698
+ if (with_comments) { algorithmURI = Canonicalizer.ALGO_ID_C14N11_WITH_COMMENTS; }
699
+ else { algorithmURI = Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS; }
700
+ }
701
+ try {
702
+ Canonicalizer canonicalizer = Canonicalizer.getInstance(algorithmURI);
703
+ XmlNode startingNode = getStartingNode(block);
704
+ byte[] result;
705
+ CanonicalFilter filter = new CanonicalFilter(context, block);
706
+ if (inclusive_namespace == null) {
707
+ result = canonicalizer.canonicalizeSubtree(startingNode.getNode(), filter);
708
+ } else {
709
+ result = canonicalizer.canonicalizeSubtree(startingNode.getNode(), inclusive_namespace, filter);
710
+ }
711
+ return RubyString.newString(context.runtime, new ByteList(result, UTF8Encoding.INSTANCE));
712
+ } catch (CanonicalizationException e) {
713
+ // TODO Auto-generated catch block
714
+ e.printStackTrace();
715
+ }
716
+ return context.nil;
717
+ }
718
+
719
+ private XmlNode
720
+ getStartingNode(Block block)
721
+ {
722
+ if (block.isGiven()) {
723
+ IRubyObject boundSelf = block.getBinding().getSelf();
724
+ if (boundSelf instanceof XmlNode) { return (XmlNode) boundSelf; }
725
+ }
726
+ return this;
727
+ }
728
+
729
+ public void
730
+ resetNamespaceCache(ThreadContext context)
731
+ {
732
+ nsCache = new NokogiriNamespaceCache();
733
+ createAndCacheNamespaces(context.runtime, node);
734
+ }
633
735
  }