nokogiri-backport 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (239) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE-DEPENDENCIES.md +1682 -0
  4. data/LICENSE.md +9 -0
  5. data/README.md +272 -0
  6. data/bin/nokogiri +118 -0
  7. data/dependencies.yml +74 -0
  8. data/ext/java/nokogiri/EncodingHandler.java +124 -0
  9. data/ext/java/nokogiri/HtmlDocument.java +178 -0
  10. data/ext/java/nokogiri/HtmlElementDescription.java +148 -0
  11. data/ext/java/nokogiri/HtmlEntityLookup.java +79 -0
  12. data/ext/java/nokogiri/HtmlSaxParserContext.java +282 -0
  13. data/ext/java/nokogiri/HtmlSaxPushParser.java +222 -0
  14. data/ext/java/nokogiri/NokogiriService.java +597 -0
  15. data/ext/java/nokogiri/XmlAttr.java +162 -0
  16. data/ext/java/nokogiri/XmlAttributeDecl.java +129 -0
  17. data/ext/java/nokogiri/XmlCdata.java +82 -0
  18. data/ext/java/nokogiri/XmlComment.java +97 -0
  19. data/ext/java/nokogiri/XmlDocument.java +633 -0
  20. data/ext/java/nokogiri/XmlDocumentFragment.java +185 -0
  21. data/ext/java/nokogiri/XmlDtd.java +481 -0
  22. data/ext/java/nokogiri/XmlElement.java +68 -0
  23. data/ext/java/nokogiri/XmlElementContent.java +382 -0
  24. data/ext/java/nokogiri/XmlElementDecl.java +147 -0
  25. data/ext/java/nokogiri/XmlEntityDecl.java +157 -0
  26. data/ext/java/nokogiri/XmlEntityReference.java +101 -0
  27. data/ext/java/nokogiri/XmlNamespace.java +199 -0
  28. data/ext/java/nokogiri/XmlNode.java +1684 -0
  29. data/ext/java/nokogiri/XmlNodeSet.java +434 -0
  30. data/ext/java/nokogiri/XmlProcessingInstruction.java +100 -0
  31. data/ext/java/nokogiri/XmlReader.java +531 -0
  32. data/ext/java/nokogiri/XmlRelaxng.java +151 -0
  33. data/ext/java/nokogiri/XmlSaxParserContext.java +374 -0
  34. data/ext/java/nokogiri/XmlSaxPushParser.java +286 -0
  35. data/ext/java/nokogiri/XmlSchema.java +388 -0
  36. data/ext/java/nokogiri/XmlSyntaxError.java +138 -0
  37. data/ext/java/nokogiri/XmlText.java +110 -0
  38. data/ext/java/nokogiri/XmlXpathContext.java +301 -0
  39. data/ext/java/nokogiri/XsltStylesheet.java +347 -0
  40. data/ext/java/nokogiri/internals/ClosedStreamException.java +10 -0
  41. data/ext/java/nokogiri/internals/HtmlDomParserContext.java +252 -0
  42. data/ext/java/nokogiri/internals/IgnoreSchemaErrorsErrorHandler.java +20 -0
  43. data/ext/java/nokogiri/internals/NokogiriBlockingQueueInputStream.java +151 -0
  44. data/ext/java/nokogiri/internals/NokogiriDomParser.java +116 -0
  45. data/ext/java/nokogiri/internals/NokogiriEntityResolver.java +121 -0
  46. data/ext/java/nokogiri/internals/NokogiriErrorHandler.java +69 -0
  47. data/ext/java/nokogiri/internals/NokogiriHandler.java +327 -0
  48. data/ext/java/nokogiri/internals/NokogiriHelpers.java +734 -0
  49. data/ext/java/nokogiri/internals/NokogiriNamespaceCache.java +217 -0
  50. data/ext/java/nokogiri/internals/NokogiriNamespaceContext.java +127 -0
  51. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java +100 -0
  52. data/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +121 -0
  53. data/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +78 -0
  54. data/ext/java/nokogiri/internals/NokogiriXPathFunction.java +180 -0
  55. data/ext/java/nokogiri/internals/NokogiriXPathFunctionResolver.java +72 -0
  56. data/ext/java/nokogiri/internals/NokogiriXPathVariableResolver.java +60 -0
  57. data/ext/java/nokogiri/internals/NokogiriXsltErrorListener.java +87 -0
  58. data/ext/java/nokogiri/internals/ParserContext.java +259 -0
  59. data/ext/java/nokogiri/internals/ReaderNode.java +488 -0
  60. data/ext/java/nokogiri/internals/SaveContextVisitor.java +778 -0
  61. data/ext/java/nokogiri/internals/SchemaErrorHandler.java +73 -0
  62. data/ext/java/nokogiri/internals/XalanDTMManagerPatch.java +168 -0
  63. data/ext/java/nokogiri/internals/XmlDeclHandler.java +42 -0
  64. data/ext/java/nokogiri/internals/XmlDomParserContext.java +274 -0
  65. data/ext/java/nokogiri/internals/XmlSaxParser.java +65 -0
  66. data/ext/java/nokogiri/internals/c14n/AttrCompare.java +119 -0
  67. data/ext/java/nokogiri/internals/c14n/C14nHelper.java +159 -0
  68. data/ext/java/nokogiri/internals/c14n/CanonicalFilter.java +37 -0
  69. data/ext/java/nokogiri/internals/c14n/CanonicalizationException.java +93 -0
  70. data/ext/java/nokogiri/internals/c14n/Canonicalizer.java +252 -0
  71. data/ext/java/nokogiri/internals/c14n/Canonicalizer11.java +639 -0
  72. data/ext/java/nokogiri/internals/c14n/Canonicalizer11_OmitComments.java +38 -0
  73. data/ext/java/nokogiri/internals/c14n/Canonicalizer11_WithComments.java +38 -0
  74. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315.java +367 -0
  75. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315Excl.java +295 -0
  76. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315ExclOmitComments.java +40 -0
  77. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315ExclWithComments.java +44 -0
  78. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315OmitComments.java +44 -0
  79. data/ext/java/nokogiri/internals/c14n/Canonicalizer20010315WithComments.java +43 -0
  80. data/ext/java/nokogiri/internals/c14n/CanonicalizerBase.java +630 -0
  81. data/ext/java/nokogiri/internals/c14n/CanonicalizerPhysical.java +173 -0
  82. data/ext/java/nokogiri/internals/c14n/CanonicalizerSpi.java +76 -0
  83. data/ext/java/nokogiri/internals/c14n/Constants.java +42 -0
  84. data/ext/java/nokogiri/internals/c14n/ElementProxy.java +293 -0
  85. data/ext/java/nokogiri/internals/c14n/HelperNodeList.java +93 -0
  86. data/ext/java/nokogiri/internals/c14n/IgnoreAllErrorHandler.java +79 -0
  87. data/ext/java/nokogiri/internals/c14n/InclusiveNamespaces.java +166 -0
  88. data/ext/java/nokogiri/internals/c14n/InvalidCanonicalizerException.java +76 -0
  89. data/ext/java/nokogiri/internals/c14n/NameSpaceSymbTable.java +402 -0
  90. data/ext/java/nokogiri/internals/c14n/NodeFilter.java +51 -0
  91. data/ext/java/nokogiri/internals/c14n/UtfHelpper.java +179 -0
  92. data/ext/java/nokogiri/internals/c14n/XMLUtils.java +507 -0
  93. data/ext/java/nokogiri/internals/dom2dtm/DOM2DTM.java +1745 -0
  94. data/ext/java/nokogiri/internals/dom2dtm/DOM2DTMdefaultNamespaceDeclarationNode.java +685 -0
  95. data/ext/nokogiri/depend +477 -0
  96. data/ext/nokogiri/extconf.rb +836 -0
  97. data/ext/nokogiri/html_document.c +171 -0
  98. data/ext/nokogiri/html_document.h +10 -0
  99. data/ext/nokogiri/html_element_description.c +279 -0
  100. data/ext/nokogiri/html_element_description.h +10 -0
  101. data/ext/nokogiri/html_entity_lookup.c +32 -0
  102. data/ext/nokogiri/html_entity_lookup.h +8 -0
  103. data/ext/nokogiri/html_sax_parser_context.c +116 -0
  104. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  105. data/ext/nokogiri/html_sax_push_parser.c +87 -0
  106. data/ext/nokogiri/html_sax_push_parser.h +9 -0
  107. data/ext/nokogiri/nokogiri.c +135 -0
  108. data/ext/nokogiri/nokogiri.h +130 -0
  109. data/ext/nokogiri/xml_attr.c +103 -0
  110. data/ext/nokogiri/xml_attr.h +9 -0
  111. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  112. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  113. data/ext/nokogiri/xml_cdata.c +62 -0
  114. data/ext/nokogiri/xml_cdata.h +9 -0
  115. data/ext/nokogiri/xml_comment.c +69 -0
  116. data/ext/nokogiri/xml_comment.h +9 -0
  117. data/ext/nokogiri/xml_document.c +622 -0
  118. data/ext/nokogiri/xml_document.h +23 -0
  119. data/ext/nokogiri/xml_document_fragment.c +48 -0
  120. data/ext/nokogiri/xml_document_fragment.h +10 -0
  121. data/ext/nokogiri/xml_dtd.c +202 -0
  122. data/ext/nokogiri/xml_dtd.h +10 -0
  123. data/ext/nokogiri/xml_element_content.c +123 -0
  124. data/ext/nokogiri/xml_element_content.h +10 -0
  125. data/ext/nokogiri/xml_element_decl.c +69 -0
  126. data/ext/nokogiri/xml_element_decl.h +9 -0
  127. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  128. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  129. data/ext/nokogiri/xml_entity_decl.c +110 -0
  130. data/ext/nokogiri/xml_entity_decl.h +10 -0
  131. data/ext/nokogiri/xml_entity_reference.c +52 -0
  132. data/ext/nokogiri/xml_entity_reference.h +9 -0
  133. data/ext/nokogiri/xml_io.c +63 -0
  134. data/ext/nokogiri/xml_io.h +11 -0
  135. data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
  136. data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
  137. data/ext/nokogiri/xml_namespace.c +111 -0
  138. data/ext/nokogiri/xml_namespace.h +14 -0
  139. data/ext/nokogiri/xml_node.c +1773 -0
  140. data/ext/nokogiri/xml_node.h +13 -0
  141. data/ext/nokogiri/xml_node_set.c +486 -0
  142. data/ext/nokogiri/xml_node_set.h +12 -0
  143. data/ext/nokogiri/xml_processing_instruction.c +56 -0
  144. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  145. data/ext/nokogiri/xml_reader.c +657 -0
  146. data/ext/nokogiri/xml_reader.h +10 -0
  147. data/ext/nokogiri/xml_relax_ng.c +179 -0
  148. data/ext/nokogiri/xml_relax_ng.h +9 -0
  149. data/ext/nokogiri/xml_sax_parser.c +305 -0
  150. data/ext/nokogiri/xml_sax_parser.h +39 -0
  151. data/ext/nokogiri/xml_sax_parser_context.c +262 -0
  152. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  153. data/ext/nokogiri/xml_sax_push_parser.c +159 -0
  154. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  155. data/ext/nokogiri/xml_schema.c +276 -0
  156. data/ext/nokogiri/xml_schema.h +9 -0
  157. data/ext/nokogiri/xml_syntax_error.c +64 -0
  158. data/ext/nokogiri/xml_syntax_error.h +13 -0
  159. data/ext/nokogiri/xml_text.c +52 -0
  160. data/ext/nokogiri/xml_text.h +9 -0
  161. data/ext/nokogiri/xml_xpath_context.c +374 -0
  162. data/ext/nokogiri/xml_xpath_context.h +10 -0
  163. data/ext/nokogiri/xslt_stylesheet.c +263 -0
  164. data/ext/nokogiri/xslt_stylesheet.h +14 -0
  165. data/lib/isorelax.jar +0 -0
  166. data/lib/jing.jar +0 -0
  167. data/lib/nekodtd.jar +0 -0
  168. data/lib/nekohtml.jar +0 -0
  169. data/lib/nokogiri/css/node.rb +53 -0
  170. data/lib/nokogiri/css/parser.rb +751 -0
  171. data/lib/nokogiri/css/parser.y +272 -0
  172. data/lib/nokogiri/css/parser_extras.rb +94 -0
  173. data/lib/nokogiri/css/syntax_error.rb +8 -0
  174. data/lib/nokogiri/css/tokenizer.rb +154 -0
  175. data/lib/nokogiri/css/tokenizer.rex +55 -0
  176. data/lib/nokogiri/css/xpath_visitor.rb +260 -0
  177. data/lib/nokogiri/css.rb +28 -0
  178. data/lib/nokogiri/decorators/slop.rb +43 -0
  179. data/lib/nokogiri/html/builder.rb +36 -0
  180. data/lib/nokogiri/html/document.rb +322 -0
  181. data/lib/nokogiri/html/document_fragment.rb +50 -0
  182. data/lib/nokogiri/html/element_description.rb +24 -0
  183. data/lib/nokogiri/html/element_description_defaults.rb +672 -0
  184. data/lib/nokogiri/html/entity_lookup.rb +14 -0
  185. data/lib/nokogiri/html/sax/parser.rb +63 -0
  186. data/lib/nokogiri/html/sax/parser_context.rb +17 -0
  187. data/lib/nokogiri/html/sax/push_parser.rb +37 -0
  188. data/lib/nokogiri/html.rb +38 -0
  189. data/lib/nokogiri/jruby/dependencies.rb +20 -0
  190. data/lib/nokogiri/syntax_error.rb +5 -0
  191. data/lib/nokogiri/version/constant.rb +5 -0
  192. data/lib/nokogiri/version/info.rb +182 -0
  193. data/lib/nokogiri/version.rb +3 -0
  194. data/lib/nokogiri/xml/attr.rb +15 -0
  195. data/lib/nokogiri/xml/attribute_decl.rb +19 -0
  196. data/lib/nokogiri/xml/builder.rb +447 -0
  197. data/lib/nokogiri/xml/cdata.rb +12 -0
  198. data/lib/nokogiri/xml/character_data.rb +8 -0
  199. data/lib/nokogiri/xml/document.rb +290 -0
  200. data/lib/nokogiri/xml/document_fragment.rb +159 -0
  201. data/lib/nokogiri/xml/dtd.rb +33 -0
  202. data/lib/nokogiri/xml/element_content.rb +37 -0
  203. data/lib/nokogiri/xml/element_decl.rb +14 -0
  204. data/lib/nokogiri/xml/entity_decl.rb +20 -0
  205. data/lib/nokogiri/xml/entity_reference.rb +19 -0
  206. data/lib/nokogiri/xml/namespace.rb +14 -0
  207. data/lib/nokogiri/xml/node/save_options.rb +62 -0
  208. data/lib/nokogiri/xml/node.rb +1240 -0
  209. data/lib/nokogiri/xml/node_set.rb +372 -0
  210. data/lib/nokogiri/xml/notation.rb +7 -0
  211. data/lib/nokogiri/xml/parse_options.rb +127 -0
  212. data/lib/nokogiri/xml/pp/character_data.rb +19 -0
  213. data/lib/nokogiri/xml/pp/node.rb +57 -0
  214. data/lib/nokogiri/xml/pp.rb +3 -0
  215. data/lib/nokogiri/xml/processing_instruction.rb +9 -0
  216. data/lib/nokogiri/xml/reader.rb +116 -0
  217. data/lib/nokogiri/xml/relax_ng.rb +37 -0
  218. data/lib/nokogiri/xml/sax/document.rb +172 -0
  219. data/lib/nokogiri/xml/sax/parser.rb +123 -0
  220. data/lib/nokogiri/xml/sax/parser_context.rb +17 -0
  221. data/lib/nokogiri/xml/sax/push_parser.rb +61 -0
  222. data/lib/nokogiri/xml/sax.rb +5 -0
  223. data/lib/nokogiri/xml/schema.rb +72 -0
  224. data/lib/nokogiri/xml/searchable.rb +239 -0
  225. data/lib/nokogiri/xml/syntax_error.rb +71 -0
  226. data/lib/nokogiri/xml/text.rb +10 -0
  227. data/lib/nokogiri/xml/xpath/syntax_error.rb +12 -0
  228. data/lib/nokogiri/xml/xpath.rb +11 -0
  229. data/lib/nokogiri/xml/xpath_context.rb +17 -0
  230. data/lib/nokogiri/xml.rb +76 -0
  231. data/lib/nokogiri/xslt/stylesheet.rb +26 -0
  232. data/lib/nokogiri/xslt.rb +57 -0
  233. data/lib/nokogiri.rb +144 -0
  234. data/lib/serializer.jar +0 -0
  235. data/lib/xalan.jar +0 -0
  236. data/lib/xercesImpl.jar +0 -0
  237. data/lib/xml-apis.jar +0 -0
  238. data/lib/xsd/xmlparser/nokogiri.rb +103 -0
  239. metadata +531 -0
@@ -0,0 +1,1745 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+ package nokogiri.internals.dom2dtm;
19
+
20
+ import javax.xml.transform.SourceLocator;
21
+ import javax.xml.transform.dom.DOMSource;
22
+
23
+ import org.apache.xml.dtm.DTM;
24
+ import org.apache.xml.dtm.DTMManager;
25
+ import org.apache.xml.dtm.DTMWSFilter;
26
+ import org.apache.xml.dtm.ref.DTMDefaultBaseIterators;
27
+ import org.apache.xml.dtm.ref.DTMManagerDefault;
28
+ import org.apache.xml.dtm.ref.ExpandedNameTable;
29
+ import org.apache.xml.dtm.ref.IncrementalSAXSource;
30
+ import org.apache.xml.res.XMLErrorResources;
31
+ import org.apache.xml.res.XMLMessages;
32
+ import org.apache.xml.utils.FastStringBuffer;
33
+ import org.apache.xml.utils.QName;
34
+ import org.apache.xml.utils.StringBufferPool;
35
+ import org.apache.xml.utils.TreeWalker;
36
+ import org.apache.xml.utils.XMLCharacterRecognizer;
37
+ import org.apache.xml.utils.XMLString;
38
+ import org.apache.xml.utils.XMLStringFactory;
39
+ import org.w3c.dom.Attr;
40
+ import org.w3c.dom.Document;
41
+ import org.w3c.dom.DocumentType;
42
+ import org.w3c.dom.Element;
43
+ import org.w3c.dom.Entity;
44
+ import org.w3c.dom.NamedNodeMap;
45
+ import org.w3c.dom.Node;
46
+ import org.xml.sax.ContentHandler;
47
+
48
+ /** The <code>DOM2DTM</code> class serves up a DOM's contents via the
49
+ * DTM API.
50
+ *
51
+ * Note that it doesn't necessarily represent a full Document
52
+ * tree. You can wrap a DOM2DTM around a specific node and its subtree
53
+ * and the right things should happen. (I don't _think_ we currently
54
+ * support DocumentFrgment nodes as roots, though that might be worth
55
+ * considering.)
56
+ *
57
+ * Note too that we do not currently attempt to track document
58
+ * mutation. If you alter the DOM after wrapping DOM2DTM around it,
59
+ * all bets are off.
60
+ * */
61
+ public class DOM2DTM extends DTMDefaultBaseIterators
62
+ {
63
+ // static final boolean JJK_DEBUG=false;
64
+ // static final boolean JJK_NEWCODE=true;
65
+
66
+ /** Manefest constant
67
+ */
68
+ static final String NAMESPACE_DECL_NS="http://www.w3.org/XML/1998/namespace";
69
+
70
+ /** The current position in the DOM tree. Last node examined for
71
+ * possible copying to DTM. */
72
+ transient private Node m_pos;
73
+ /** The current position in the DTM tree. Who children get appended to. */
74
+ private int m_last_parent=0;
75
+ /** The current position in the DTM tree. Who children reference as their
76
+ * previous sib. */
77
+ private int m_last_kid=NULL;
78
+
79
+ /** The top of the subtree.
80
+ * %REVIEW%: 'may not be the same as m_context if "//foo" pattern.'
81
+ * */
82
+ transient private Node m_root;
83
+
84
+ /** True iff the first element has been processed. This is used to control
85
+ synthesis of the implied xml: namespace declaration node. */
86
+ boolean m_processedFirstElement=false;
87
+
88
+ /** true if ALL the nodes in the m_root subtree have been processed;
89
+ * false if our incremental build has not yet finished scanning the
90
+ * DOM tree. */
91
+ transient private boolean m_nodesAreProcessed;
92
+
93
+ /** The node objects. The instance part of the handle indexes
94
+ * directly into this vector. Each DTM node may actually be
95
+ * composed of several DOM nodes (for example, if logically-adjacent
96
+ * Text/CDATASection nodes in the DOM have been coalesced into a
97
+ * single DTM Text node); this table points only to the first in
98
+ * that sequence. */
99
+ protected final java.util.List<Node> m_nodes = new java.util.ArrayList<Node>(12);
100
+
101
+ /**
102
+ * Construct a DOM2DTM object from a DOM node.
103
+ *
104
+ * @param mgr The DTMManager who owns this DTM.
105
+ * @param domSource the DOM source that this DTM will wrap.
106
+ * @param dtmIdentity The DTM identity ID for this DTM.
107
+ * @param whiteSpaceFilter The white space filter for this DTM, which may
108
+ * be null.
109
+ * @param xstringfactory XMLString factory for creating character content.
110
+ * @param doIndexing true if the caller considers it worth it to use
111
+ * indexing schemes.
112
+ */
113
+ public DOM2DTM(DTMManager mgr, DOMSource domSource,
114
+ int dtmIdentity, DTMWSFilter whiteSpaceFilter,
115
+ XMLStringFactory xstringfactory,
116
+ boolean doIndexing)
117
+ {
118
+ super(mgr, domSource, dtmIdentity, whiteSpaceFilter,
119
+ xstringfactory, doIndexing);
120
+
121
+ // Initialize DOM navigation
122
+ m_pos=m_root = domSource.getNode();
123
+ // Initialize DTM navigation
124
+ m_last_parent=m_last_kid=NULL;
125
+ m_last_kid=addNode(m_root, m_last_parent,m_last_kid, NULL);
126
+
127
+ // Apparently the domSource root may not actually be the
128
+ // Document node. If it's an Element node, we need to immediately
129
+ // add its attributes. Adapted from nextNode().
130
+ // %REVIEW% Move this logic into addNode and recurse? Cleaner!
131
+ //
132
+ // (If it's an EntityReference node, we're probably in
133
+ // seriously bad trouble. For now
134
+ // I'm just hoping nobody is ever quite that foolish... %REVIEW%)
135
+ //
136
+ // %ISSUE% What about inherited namespaces in this case?
137
+ // Do we need to special-case initialize them into the DTM model?
138
+ if(ELEMENT_NODE == m_root.getNodeType())
139
+ {
140
+ NamedNodeMap attrs=m_root.getAttributes();
141
+ int attrsize=(attrs==null) ? 0 : attrs.getLength();
142
+ if(attrsize>0)
143
+ {
144
+ int attrIndex=NULL; // start with no previous sib
145
+ for(int i=0;i<attrsize;++i)
146
+ {
147
+ // No need to force nodetype in this case;
148
+ // addNode() will take care of switching it from
149
+ // Attr to Namespace if necessary.
150
+ attrIndex=addNode(attrs.item(i),0,attrIndex,NULL);
151
+ m_firstch.setElementAt(DTM.NULL,attrIndex);
152
+ }
153
+ // Terminate list of attrs, and make sure they aren't
154
+ // considered children of the element
155
+ m_nextsib.setElementAt(DTM.NULL,attrIndex);
156
+
157
+ // IMPORTANT: This does NOT change m_last_parent or m_last_kid!
158
+ } // if attrs exist
159
+ } //if(ELEMENT_NODE)
160
+
161
+ // Initialize DTM-completed status
162
+ m_nodesAreProcessed = false;
163
+ }
164
+
165
+ /**
166
+ * Construct the node map from the node.
167
+ *
168
+ * @param node The node that is to be added to the DTM.
169
+ * @param parentIndex The current parent index.
170
+ * @param previousSibling The previous sibling index.
171
+ * @param forceNodeType If not DTM.NULL, overrides the DOM node type.
172
+ * Used to force nodes to Text rather than CDATASection when their
173
+ * coalesced value includes ordinary Text nodes (current DTM behavior).
174
+ *
175
+ * @return The index identity of the node that was added.
176
+ */
177
+ protected int addNode(Node node, int parentIndex,
178
+ int previousSibling, int forceNodeType)
179
+ {
180
+ int nodeIndex = m_nodes.size();
181
+
182
+ // Have we overflowed a DTM Identity's addressing range?
183
+ if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
184
+ {
185
+ try
186
+ {
187
+ if(m_mgr==null)
188
+ throw new ClassCastException();
189
+
190
+ // Handle as Extended Addressing
191
+ DTMManagerDefault mgrD=(DTMManagerDefault)m_mgr;
192
+ int id=mgrD.getFirstFreeDTMID();
193
+ mgrD.addDTM(this,id,nodeIndex);
194
+ m_dtmIdent.addElement(id<<DTMManager.IDENT_DTM_NODE_BITS);
195
+ }
196
+ catch(ClassCastException e)
197
+ {
198
+ // %REVIEW% Wrong error message, but I've been told we're trying
199
+ // not to add messages right not for I18N reasons.
200
+ // %REVIEW% Should this be a Fatal Error?
201
+ error(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null));//"No more DTM IDs are available";
202
+ }
203
+ }
204
+
205
+ m_size++;
206
+ // ensureSize(nodeIndex);
207
+
208
+ int type;
209
+ if(NULL==forceNodeType)
210
+ type = node.getNodeType();
211
+ else
212
+ type=forceNodeType;
213
+
214
+ // %REVIEW% The Namespace Spec currently says that Namespaces are
215
+ // processed in a non-namespace-aware manner, by matching the
216
+ // QName, even though there is in fact a namespace assigned to
217
+ // these nodes in the DOM. If and when that changes, we will have
218
+ // to consider whether we check the namespace-for-namespaces
219
+ // rather than the node name.
220
+ //
221
+ // %TBD% Note that the DOM does not necessarily explicitly declare
222
+ // all the namespaces it uses. DOM Level 3 will introduce a
223
+ // namespace-normalization operation which reconciles that, and we
224
+ // can request that users invoke it or otherwise ensure that the
225
+ // tree is namespace-well-formed before passing the DOM to Xalan.
226
+ // But if they don't, what should we do about it? We probably
227
+ // don't want to alter the source DOM (and may not be able to do
228
+ // so if it's read-only). The best available answer might be to
229
+ // synthesize additional DTM Namespace Nodes that don't correspond
230
+ // to DOM Attr Nodes.
231
+ if (Node.ATTRIBUTE_NODE == type)
232
+ {
233
+ String name = node.getNodeName();
234
+
235
+ if (name.startsWith("xmlns:") || name.equals("xmlns"))
236
+ {
237
+ type = DTM.NAMESPACE_NODE;
238
+ }
239
+ }
240
+
241
+ m_nodes.add(node);
242
+
243
+ m_firstch.setElementAt(NOTPROCESSED,nodeIndex);
244
+ m_nextsib.setElementAt(NOTPROCESSED,nodeIndex);
245
+ m_prevsib.setElementAt(previousSibling,nodeIndex);
246
+ m_parent.setElementAt(parentIndex,nodeIndex);
247
+
248
+ if(DTM.NULL != parentIndex &&
249
+ type != DTM.ATTRIBUTE_NODE &&
250
+ type != DTM.NAMESPACE_NODE)
251
+ {
252
+ // If the DTM parent had no children, this becomes its first child.
253
+ if(NOTPROCESSED == m_firstch.elementAt(parentIndex))
254
+ m_firstch.setElementAt(nodeIndex,parentIndex);
255
+ }
256
+
257
+ String nsURI = node.getNamespaceURI();
258
+
259
+ // Deal with the difference between Namespace spec and XSLT
260
+ // definitions of local name. (The former says PIs don't have
261
+ // localnames; the latter says they do.)
262
+ String localName = (type == Node.PROCESSING_INSTRUCTION_NODE) ?
263
+ node.getNodeName() :
264
+ node.getLocalName();
265
+
266
+ // Hack to make DOM1 sort of work...
267
+ if(((type == Node.ELEMENT_NODE) || (type == Node.ATTRIBUTE_NODE))
268
+ && null == localName)
269
+ localName = node.getNodeName(); // -sb
270
+
271
+ ExpandedNameTable exnt = m_expandedNameTable;
272
+
273
+ // %TBD% Nodes created with the old non-namespace-aware DOM
274
+ // calls createElement() and createAttribute() will never have a
275
+ // localname. That will cause their expandedNameID to be just the
276
+ // nodeType... which will keep them from being matched
277
+ // successfully by name. Since the DOM makes no promise that
278
+ // those will participate in namespace processing, this is
279
+ // officially accepted as Not Our Fault. But it might be nice to
280
+ // issue a diagnostic message!
281
+ if(node.getLocalName()==null &&
282
+ (type==Node.ELEMENT_NODE || type==Node.ATTRIBUTE_NODE))
283
+ {
284
+ // warning("DOM 'level 1' node "+node.getNodeName()+" won't be mapped properly in DOM2DTM.");
285
+ }
286
+
287
+ int expandedNameID = (null != localName)
288
+ ? exnt.getExpandedTypeID(nsURI, localName, type) :
289
+ exnt.getExpandedTypeID(type);
290
+
291
+ m_exptype.setElementAt(expandedNameID,nodeIndex);
292
+
293
+ indexNode(expandedNameID, nodeIndex);
294
+
295
+ if (DTM.NULL != previousSibling)
296
+ m_nextsib.setElementAt(nodeIndex,previousSibling);
297
+
298
+ // This should be done after m_exptype has been set, and probably should
299
+ // always be the last thing we do
300
+ if (type == DTM.NAMESPACE_NODE)
301
+ declareNamespaceInContext(parentIndex,nodeIndex);
302
+
303
+ return nodeIndex;
304
+ }
305
+
306
+ /**
307
+ * Get the number of nodes that have been added.
308
+ */
309
+ public int getNumberOfNodes()
310
+ {
311
+ return m_nodes.size();
312
+ }
313
+
314
+ /**
315
+ * This method iterates to the next node that will be added to the table.
316
+ * Each call to this method adds a new node to the table, unless the end
317
+ * is reached, in which case it returns null.
318
+ *
319
+ * @return The true if a next node is found or false if
320
+ * there are no more nodes.
321
+ */
322
+ protected boolean nextNode()
323
+ {
324
+ // Non-recursive one-fetch-at-a-time depth-first traversal with
325
+ // attribute/namespace nodes and white-space stripping.
326
+ // Navigating the DOM is simple, navigating the DTM is simple;
327
+ // keeping track of both at once is a trifle baroque but at least
328
+ // we've avoided most of the special cases.
329
+ if (m_nodesAreProcessed)
330
+ return false;
331
+
332
+ // %REVIEW% Is this local copy Really Useful from a performance
333
+ // point of view? Or is this a false microoptimization?
334
+ Node pos=m_pos;
335
+ Node next=null;
336
+ int nexttype=NULL;
337
+
338
+ // Navigate DOM tree
339
+ do
340
+ {
341
+ // Look down to first child.
342
+ if (pos.hasChildNodes())
343
+ {
344
+ next = pos.getFirstChild();
345
+
346
+ // %REVIEW% There's probably a more elegant way to skip
347
+ // the doctype. (Just let it go and Suppress it?
348
+ if(next!=null && DOCUMENT_TYPE_NODE==next.getNodeType())
349
+ next=next.getNextSibling();
350
+
351
+ // Push DTM context -- except for children of Entity References,
352
+ // which have no DTM equivalent and cause no DTM navigation.
353
+ if(ENTITY_REFERENCE_NODE!=pos.getNodeType())
354
+ {
355
+ m_last_parent=m_last_kid;
356
+ m_last_kid=NULL;
357
+ // Whitespace-handler context stacking
358
+ if(null != m_wsfilter)
359
+ {
360
+ short wsv =
361
+ m_wsfilter.getShouldStripSpace(makeNodeHandle(m_last_parent),this);
362
+ boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
363
+ ? getShouldStripWhitespace()
364
+ : (DTMWSFilter.STRIP == wsv);
365
+ pushShouldStripWhitespace(shouldStrip);
366
+ } // if(m_wsfilter)
367
+ }
368
+ }
369
+
370
+ // If that fails, look up and right (but not past root!)
371
+ else
372
+ {
373
+ if(m_last_kid!=NULL)
374
+ {
375
+ // Last node posted at this level had no more children
376
+ // If it has _no_ children, we need to record that.
377
+ if(m_firstch.elementAt(m_last_kid)==NOTPROCESSED)
378
+ m_firstch.setElementAt(NULL,m_last_kid);
379
+ }
380
+
381
+ while(m_last_parent != NULL)
382
+ {
383
+ // %REVIEW% There's probably a more elegant way to
384
+ // skip the doctype. (Just let it go and Suppress it?
385
+ next = pos.getNextSibling();
386
+ if(next!=null && DOCUMENT_TYPE_NODE==next.getNodeType())
387
+ next=next.getNextSibling();
388
+
389
+ if(next!=null)
390
+ break; // Found it!
391
+
392
+ // No next-sibling found. Pop the DOM.
393
+ pos=pos.getParentNode();
394
+ // if(pos==null)
395
+ // {
396
+ // // %TBD% Should never arise, but I want to be sure of that...
397
+ // if(JJK_DEBUG)
398
+ // {
399
+ // System.out.println("***** DOM2DTM Pop Control Flow problem");
400
+ // for(;;); // Freeze right here!
401
+ // }
402
+ // }
403
+
404
+ // The only parents in the DTM are Elements. However,
405
+ // the DOM could contain EntityReferences. If we
406
+ // encounter one, pop it _without_ popping DTM.
407
+ if(pos!=null && ENTITY_REFERENCE_NODE == pos.getNodeType())
408
+ {
409
+ // // Nothing needs doing
410
+ // if(JJK_DEBUG) System.out.println("***** DOM2DTM popping EntRef");
411
+ }
412
+ else
413
+ {
414
+ popShouldStripWhitespace();
415
+ // Fix and pop DTM
416
+ if(m_last_kid==NULL)
417
+ m_firstch.setElementAt(NULL,m_last_parent); // Popping from an element
418
+ else
419
+ m_nextsib.setElementAt(NULL,m_last_kid); // Popping from anything else
420
+ m_last_parent=m_parent.elementAt(m_last_kid=m_last_parent);
421
+ }
422
+ }
423
+ if(m_last_parent==NULL) next=null;
424
+ }
425
+
426
+ if(next!=null) nexttype=next.getNodeType();
427
+
428
+ // If it's an entity ref, advance past it.
429
+ //
430
+ // %REVIEW% Should we let this out the door and just suppress it?
431
+ // More work, but simpler code, more likely to be correct, and
432
+ // it doesn't happen very often. We'd get rid of the loop too.
433
+ if (ENTITY_REFERENCE_NODE == nexttype) pos=next;
434
+ }
435
+ while (ENTITY_REFERENCE_NODE == nexttype);
436
+
437
+ // Did we run out of the tree?
438
+ if(next==null)
439
+ {
440
+ m_nextsib.setElementAt(NULL,0);
441
+ m_nodesAreProcessed = true;
442
+ m_pos=null;
443
+
444
+ // if(JJK_DEBUG)
445
+ // {
446
+ // System.out.println("***** DOM2DTM Crosscheck:");
447
+ // for(int i=0;i<m_nodes.size();++i)
448
+ // System.out.println(i+":\t"+m_firstch.elementAt(i)+"\t"+m_nextsib.elementAt(i));
449
+ // }
450
+
451
+ return false;
452
+ }
453
+
454
+ // Text needs some special handling:
455
+ //
456
+ // DTM may skip whitespace. This is handled by the suppressNode flag, which
457
+ // when true will keep the DTM node from being created.
458
+ //
459
+ // DTM only directly records the first DOM node of any logically-contiguous
460
+ // sequence. The lastTextNode value will be set to the last node in the
461
+ // contiguous sequence, and -- AFTER the DTM addNode -- can be used to
462
+ // advance next over this whole block. Should be simpler than special-casing
463
+ // the above loop for "Was the logically-preceeding sibling a text node".
464
+ //
465
+ // Finally, a DTM node should be considered a CDATASection only if all the
466
+ // contiguous text it covers is CDATASections. The first Text should
467
+ // force DTM to Text.
468
+
469
+ boolean suppressNode=false;
470
+ Node lastTextNode=null;
471
+
472
+ nexttype=next.getNodeType();
473
+
474
+ // nexttype=pos.getNodeType();
475
+ if(TEXT_NODE == nexttype || CDATA_SECTION_NODE == nexttype)
476
+ {
477
+ // If filtering, initially assume we're going to suppress the node
478
+ suppressNode=((null != m_wsfilter) && getShouldStripWhitespace());
479
+
480
+ // Scan logically contiguous text (siblings, plus "flattening"
481
+ // of entity reference boundaries).
482
+ if (suppressNode) {
483
+ Node n = next;
484
+ while (n != null) {
485
+ lastTextNode=n;
486
+ // Any Text node means DTM considers it all Text
487
+ if (TEXT_NODE == n.getNodeType()) nexttype = TEXT_NODE;
488
+ // Any non-whitespace in this sequence blocks whitespace
489
+ // suppression
490
+ suppressNode &= XMLCharacterRecognizer.isWhiteSpace(n.getNodeValue());
491
+
492
+ n = logicalNextDOMTextNode(n);
493
+ }
494
+ }
495
+ }
496
+
497
+ // Special handling for PIs: Some DOMs represent the XML
498
+ // Declaration as a PI. This is officially incorrect, per the DOM
499
+ // spec, but is considered a "wrong but tolerable" temporary
500
+ // workaround pending proper handling of these fields in DOM Level
501
+ // 3. We want to recognize and reject that case.
502
+ else if(PROCESSING_INSTRUCTION_NODE==nexttype)
503
+ {
504
+ suppressNode = (pos.getNodeName().toLowerCase().equals("xml"));
505
+ }
506
+
507
+
508
+ if(!suppressNode)
509
+ {
510
+ // Inserting next. NOTE that we force the node type; for
511
+ // coalesced Text, this records CDATASections adjacent to
512
+ // ordinary Text as Text.
513
+ int nextindex=addNode(next, m_last_parent, m_last_kid, nexttype);
514
+
515
+ m_last_kid=nextindex;
516
+
517
+ if(ELEMENT_NODE == nexttype)
518
+ {
519
+ int attrIndex=NULL; // start with no previous sib
520
+ // Process attributes _now_, rather than waiting.
521
+ // Simpler control flow, makes NS cache available immediately.
522
+ NamedNodeMap attrs=next.getAttributes();
523
+ int attrsize=(attrs==null) ? 0 : attrs.getLength();
524
+ if(attrsize>0)
525
+ {
526
+ for(int i=0;i<attrsize;++i)
527
+ {
528
+ // No need to force nodetype in this case;
529
+ // addNode() will take care of switching it from
530
+ // Attr to Namespace if necessary.
531
+ attrIndex=addNode(attrs.item(i), nextindex, attrIndex, NULL);
532
+ m_firstch.setElementAt(DTM.NULL,attrIndex);
533
+
534
+ // If the xml: prefix is explicitly declared
535
+ // we don't need to synthesize one.
536
+ //
537
+ // NOTE that XML Namespaces were not originally
538
+ // defined as being namespace-aware (grrr), and
539
+ // while the W3C is planning to fix this it's
540
+ // safer for now to test the QName and trust the
541
+ // parsers to prevent anyone from redefining the
542
+ // reserved xmlns: prefix
543
+ if(!m_processedFirstElement
544
+ && "xmlns:xml".equals(attrs.item(i).getNodeName()))
545
+ m_processedFirstElement=true;
546
+ }
547
+ // Terminate list of attrs, and make sure they aren't
548
+ // considered children of the element
549
+ } // if attrs exist
550
+ if(!m_processedFirstElement)
551
+ {
552
+ // The DOM might not have an explicit declaration for the
553
+ // implicit "xml:" prefix, but the XPath data model
554
+ // requires that this appear as a Namespace Node so we
555
+ // have to synthesize one. You can think of this as
556
+ // being a default attribute defined by the XML
557
+ // Namespaces spec rather than by the DTD.
558
+ attrIndex=addNode(new DOM2DTMdefaultNamespaceDeclarationNode(
559
+ (Element)next,"xml",NAMESPACE_DECL_NS,
560
+ makeNodeHandle(((attrIndex==NULL)?nextindex:attrIndex)+1)
561
+ ),
562
+ nextindex,attrIndex,NULL);
563
+ m_firstch.setElementAt(DTM.NULL,attrIndex);
564
+ m_processedFirstElement=true;
565
+ }
566
+ if(attrIndex!=NULL) m_nextsib.setElementAt(DTM.NULL,attrIndex);
567
+ } //if(ELEMENT_NODE)
568
+ } // (if !suppressNode)
569
+
570
+ // Text postprocessing: Act on values stored above
571
+ //if(TEXT_NODE == nexttype || CDATA_SECTION_NODE == nexttype)
572
+ //{
573
+ // %TBD% If nexttype was forced to TEXT, patch the DTM node
574
+ if (lastTextNode != null) next=lastTextNode; // Advance the DOM cursor over contiguous text
575
+ //}
576
+
577
+ // Remember where we left off.
578
+ m_pos=next;
579
+ return true;
580
+ }
581
+
582
+
583
+ /**
584
+ * Return an DOM node for the given node.
585
+ *
586
+ * @param nodeHandle The node ID.
587
+ *
588
+ * @return A node representation of the DTM node.
589
+ */
590
+ public Node getNode(int nodeHandle)
591
+ {
592
+
593
+ int identity = makeNodeIdentity(nodeHandle);
594
+
595
+ return (Node) m_nodes.get(identity);
596
+ }
597
+
598
+ /**
599
+ * Get a Node from an identity index.
600
+ *
601
+ * NEEDSDOC @param nodeIdentity
602
+ *
603
+ * NEEDSDOC ($objectName$) @return
604
+ */
605
+ protected Node lookupNode(int nodeIdentity)
606
+ {
607
+ return (Node) m_nodes.get(nodeIdentity);
608
+ }
609
+
610
+ /**
611
+ * Get the next node identity value in the list, and call the iterator
612
+ * if it hasn't been added yet.
613
+ *
614
+ * @param identity The node identity (index).
615
+ * @return identity+1, or DTM.NULL.
616
+ */
617
+ protected int getNextNodeIdentity(int identity)
618
+ {
619
+
620
+ identity += 1;
621
+
622
+ if (identity >= m_nodes.size())
623
+ {
624
+ if (!nextNode())
625
+ identity = DTM.NULL;
626
+ }
627
+
628
+ return identity;
629
+ }
630
+
631
+ /**
632
+ * Get the handle from a Node.
633
+ * <p>%OPT% This will be pretty slow.</p>
634
+ *
635
+ * <p>%OPT% An XPath-like search (walk up DOM to root, tracking path;
636
+ * walk down DTM reconstructing path) might be considerably faster
637
+ * on later nodes in large documents. That might also imply improving
638
+ * this call to handle nodes which would be in this DTM but
639
+ * have not yet been built, which might or might not be a Good Thing.</p>
640
+ *
641
+ * %REVIEW% This relies on being able to test node-identity via
642
+ * object-identity. DTM2DOM proxying is a great example of a case where
643
+ * that doesn't work. DOM Level 3 will provide the isSameNode() method
644
+ * to fix that, but until then this is going to be flaky.
645
+ *
646
+ * @param node A node, which may be null.
647
+ *
648
+ * @return The node handle or <code>DTM.NULL</code>.
649
+ */
650
+ public int getHandleFromNode(Node node)
651
+ {
652
+ if (null != node)
653
+ {
654
+ int len = m_nodes.size();
655
+ boolean isMore;
656
+ int i = 0;
657
+ do
658
+ {
659
+ for (; i < len; i++)
660
+ {
661
+ if (m_nodes.get(i) == node)
662
+ return makeNodeHandle(i);
663
+ }
664
+
665
+ isMore = nextNode();
666
+
667
+ len = m_nodes.size();
668
+
669
+ }
670
+ while(isMore || i < len);
671
+ }
672
+
673
+ return DTM.NULL;
674
+ }
675
+
676
+ /** Get the handle from a Node. This is a more robust version of
677
+ * getHandleFromNode, intended to be usable by the public.
678
+ *
679
+ * <p>%OPT% This will be pretty slow.</p>
680
+ *
681
+ * %REVIEW% This relies on being able to test node-identity via
682
+ * object-identity. DTM2DOM proxying is a great example of a case where
683
+ * that doesn't work. DOM Level 3 will provide the isSameNode() method
684
+ * to fix that, but until then this is going to be flaky.
685
+ *
686
+ * @param node A node, which may be null.
687
+ *
688
+ * @return The node handle or <code>DTM.NULL</code>. */
689
+ public int getHandleOfNode(Node node)
690
+ {
691
+ if (null != node)
692
+ {
693
+ // Is Node actually within the same document? If not, don't search!
694
+ // This would be easier if m_root was always the Document node, but
695
+ // we decided to allow wrapping a DTM around a subtree.
696
+ if((m_root==node) ||
697
+ (m_root.getNodeType()==DOCUMENT_NODE &&
698
+ m_root==node.getOwnerDocument()) ||
699
+ (m_root.getNodeType()!=DOCUMENT_NODE &&
700
+ m_root.getOwnerDocument()==node.getOwnerDocument())
701
+ )
702
+ {
703
+ // If node _is_ in m_root's tree, find its handle
704
+ //
705
+ // %OPT% This check may be improved significantly when DOM
706
+ // Level 3 nodeKey and relative-order tests become
707
+ // available!
708
+ for(Node cursor=node;
709
+ cursor!=null;
710
+ cursor=
711
+ (cursor.getNodeType()!=ATTRIBUTE_NODE)
712
+ ? cursor.getParentNode()
713
+ : ((org.w3c.dom.Attr)cursor).getOwnerElement())
714
+ {
715
+ if(cursor==m_root)
716
+ // We know this node; find its handle.
717
+ return getHandleFromNode(node);
718
+ } // for ancestors of node
719
+ } // if node and m_root in same Document
720
+ } // if node!=null
721
+
722
+ return DTM.NULL;
723
+ }
724
+
725
+ /**
726
+ * Retrieves an attribute node by by qualified name and namespace URI.
727
+ *
728
+ * @param nodeHandle int Handle of the node upon which to look up this attribute..
729
+ * @param namespaceURI The namespace URI of the attribute to
730
+ * retrieve, or null.
731
+ * @param name The local name of the attribute to
732
+ * retrieve.
733
+ * @return The attribute node handle with the specified name (
734
+ * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
735
+ * attribute.
736
+ */
737
+ public int getAttributeNode(int nodeHandle, String namespaceURI,
738
+ String name)
739
+ {
740
+
741
+ // %OPT% This is probably slower than it needs to be.
742
+ if (null == namespaceURI)
743
+ namespaceURI = "";
744
+
745
+ int type = getNodeType(nodeHandle);
746
+
747
+ if (DTM.ELEMENT_NODE == type)
748
+ {
749
+
750
+ // Assume that attributes immediately follow the element.
751
+ int identity = makeNodeIdentity(nodeHandle);
752
+
753
+ while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
754
+ {
755
+ // Assume this can not be null.
756
+ type = _type(identity);
757
+
758
+ // %REVIEW%
759
+ // Should namespace nodes be retrievable DOM-style as attrs?
760
+ // If not we need a separate function... which may be desirable
761
+ // architecturally, but which is ugly from a code point of view.
762
+ // (If we REALLY insist on it, this code should become a subroutine
763
+ // of both -- retrieve the node, then test if the type matches
764
+ // what you're looking for.)
765
+ if (type == DTM.ATTRIBUTE_NODE || type==DTM.NAMESPACE_NODE)
766
+ {
767
+ Node node = lookupNode(identity);
768
+ String nodeuri = node.getNamespaceURI();
769
+
770
+ if (null == nodeuri)
771
+ nodeuri = "";
772
+
773
+ String nodelocalname = node.getLocalName();
774
+
775
+ if (nodeuri.equals(namespaceURI) && name.equals(nodelocalname))
776
+ return makeNodeHandle(identity);
777
+ }
778
+
779
+ else // if (DTM.NAMESPACE_NODE != type)
780
+ {
781
+ break;
782
+ }
783
+ }
784
+ }
785
+
786
+ return DTM.NULL;
787
+ }
788
+
789
+ /**
790
+ * Get the string-value of a node as a String object
791
+ * (see http://www.w3.org/TR/xpath#data-model
792
+ * for the definition of a node's string-value).
793
+ *
794
+ * @param nodeHandle The node ID.
795
+ *
796
+ * @return A string object that represents the string-value of the given node.
797
+ */
798
+ public XMLString getStringValue(int nodeHandle)
799
+ {
800
+
801
+ int type = getNodeType(nodeHandle);
802
+ Node node = getNode(nodeHandle);
803
+ // %TBD% If an element only has one text node, we should just use it
804
+ // directly.
805
+ if(DTM.ELEMENT_NODE == type || DTM.DOCUMENT_NODE == type
806
+ || DTM.DOCUMENT_FRAGMENT_NODE == type)
807
+ {
808
+ FastStringBuffer buf = StringBufferPool.get();
809
+ String s;
810
+
811
+ try
812
+ {
813
+ getNodeData(node, buf);
814
+
815
+ s = (buf.length() > 0) ? buf.toString() : "";
816
+ }
817
+ finally
818
+ {
819
+ StringBufferPool.free(buf);
820
+ }
821
+
822
+ return m_xstrf.newstr( s );
823
+ }
824
+ else if(TEXT_NODE == type || CDATA_SECTION_NODE == type)
825
+ {
826
+ // If this is a DTM text node, it may be made of multiple DOM text
827
+ // nodes -- including navigating into Entity References. DOM2DTM
828
+ // records the first node in the sequence and requires that we
829
+ // pick up the others when we retrieve the DTM node's value.
830
+ //
831
+ // %REVIEW% DOM Level 3 is expected to add a "whole text"
832
+ // retrieval method which performs this function for us.
833
+ FastStringBuffer buf = StringBufferPool.get();
834
+ while(node!=null)
835
+ {
836
+ buf.append(node.getNodeValue());
837
+ node=logicalNextDOMTextNode(node);
838
+ }
839
+ String s=(buf.length() > 0) ? buf.toString() : "";
840
+ StringBufferPool.free(buf);
841
+ return m_xstrf.newstr( s );
842
+ }
843
+ else
844
+ return m_xstrf.newstr( node.getNodeValue() );
845
+ }
846
+
847
+ /**
848
+ * Determine if the string-value of a node is whitespace
849
+ *
850
+ * @param nodeHandle The node Handle.
851
+ *
852
+ * @return Return true if the given node is whitespace.
853
+ */
854
+ public boolean isWhitespace(int nodeHandle)
855
+ {
856
+ int type = getNodeType(nodeHandle);
857
+ Node node = getNode(nodeHandle);
858
+ if(TEXT_NODE == type || CDATA_SECTION_NODE == type)
859
+ {
860
+ // If this is a DTM text node, it may be made of multiple DOM text
861
+ // nodes -- including navigating into Entity References. DOM2DTM
862
+ // records the first node in the sequence and requires that we
863
+ // pick up the others when we retrieve the DTM node's value.
864
+ //
865
+ // %REVIEW% DOM Level 3 is expected to add a "whole text"
866
+ // retrieval method which performs this function for us.
867
+ FastStringBuffer buf = StringBufferPool.get();
868
+ while(node!=null)
869
+ {
870
+ buf.append(node.getNodeValue());
871
+ node=logicalNextDOMTextNode(node);
872
+ }
873
+ boolean b = buf.isWhitespace(0, buf.length());
874
+ StringBufferPool.free(buf);
875
+ return b;
876
+ }
877
+ return false;
878
+ }
879
+
880
+ /**
881
+ * Retrieve the text content of a DOM subtree, appending it into a
882
+ * user-supplied FastStringBuffer object. Note that attributes are
883
+ * not considered part of the content of an element.
884
+ * <p>
885
+ * There are open questions regarding whitespace stripping.
886
+ * Currently we make no special effort in that regard, since the standard
887
+ * DOM doesn't yet provide DTD-based information to distinguish
888
+ * whitespace-in-element-context from genuine #PCDATA. Note that we
889
+ * should probably also consider xml:space if/when we address this.
890
+ * DOM Level 3 may solve the problem for us.
891
+ * <p>
892
+ * %REVIEW% Actually, since this method operates on the DOM side of the
893
+ * fence rather than the DTM side, it SHOULDN'T do
894
+ * any special handling. The DOM does what the DOM does; if you want
895
+ * DTM-level abstractions, use DTM-level methods.
896
+ *
897
+ * @param node Node whose subtree is to be walked, gathering the
898
+ * contents of all Text or CDATASection nodes.
899
+ * @param buf FastStringBuffer into which the contents of the text
900
+ * nodes are to be concatenated.
901
+ */
902
+ protected static void getNodeData(Node node, FastStringBuffer buf)
903
+ {
904
+
905
+ switch (node.getNodeType())
906
+ {
907
+ case Node.DOCUMENT_FRAGMENT_NODE :
908
+ case Node.DOCUMENT_NODE :
909
+ case Node.ELEMENT_NODE :
910
+ {
911
+ for (Node child = node.getFirstChild(); null != child;
912
+ child = child.getNextSibling())
913
+ {
914
+ getNodeData(child, buf);
915
+ }
916
+ }
917
+ break;
918
+ case Node.TEXT_NODE :
919
+ case Node.CDATA_SECTION_NODE :
920
+ case Node.ATTRIBUTE_NODE : // Never a child but might be our starting node
921
+ buf.append(node.getNodeValue());
922
+ break;
923
+ case Node.PROCESSING_INSTRUCTION_NODE :
924
+ // warning(XPATHErrorResources.WG_PARSING_AND_PREPARING);
925
+ break;
926
+ default :
927
+ // ignore
928
+ break;
929
+ }
930
+ }
931
+
932
+ /**
933
+ * Given a node handle, return its DOM-style node name. This will
934
+ * include names such as #text or #document.
935
+ *
936
+ * @param nodeHandle the id of the node.
937
+ * @return String Name of this node, which may be an empty string.
938
+ * %REVIEW% Document when empty string is possible...
939
+ * %REVIEW-COMMENT% It should never be empty, should it?
940
+ */
941
+ public String getNodeName(int nodeHandle)
942
+ {
943
+
944
+ Node node = getNode(nodeHandle);
945
+
946
+ // Assume non-null.
947
+ return node.getNodeName();
948
+ }
949
+
950
+ /**
951
+ * Given a node handle, return the XPath node name. This should be
952
+ * the name as described by the XPath data model, NOT the DOM-style
953
+ * name.
954
+ *
955
+ * @param nodeHandle the id of the node.
956
+ * @return String Name of this node, which may be an empty string.
957
+ */
958
+ public String getNodeNameX(int nodeHandle)
959
+ {
960
+
961
+ String name;
962
+ short type = getNodeType(nodeHandle);
963
+
964
+ switch (type)
965
+ {
966
+ case DTM.NAMESPACE_NODE :
967
+ {
968
+ Node node = getNode(nodeHandle);
969
+
970
+ // assume not null.
971
+ name = node.getNodeName();
972
+ if(name.startsWith("xmlns:"))
973
+ {
974
+ name = QName.getLocalPart(name);
975
+ }
976
+ else if(name.equals("xmlns"))
977
+ {
978
+ name = "";
979
+ }
980
+ }
981
+ break;
982
+ case DTM.ATTRIBUTE_NODE :
983
+ case DTM.ELEMENT_NODE :
984
+ case DTM.ENTITY_REFERENCE_NODE :
985
+ case DTM.PROCESSING_INSTRUCTION_NODE :
986
+ {
987
+ Node node = getNode(nodeHandle);
988
+
989
+ // assume not null.
990
+ name = node.getNodeName();
991
+ }
992
+ break;
993
+ default :
994
+ name = "";
995
+ }
996
+
997
+ return name;
998
+ }
999
+
1000
+ /**
1001
+ * Given a node handle, return its XPath-style localname.
1002
+ * (As defined in Namespaces, this is the portion of the name after any
1003
+ * colon character).
1004
+ *
1005
+ * @param nodeHandle the id of the node.
1006
+ * @return String Local name of this node.
1007
+ */
1008
+ public String getLocalName(int nodeHandle)
1009
+ {
1010
+ // if(JJK_NEWCODE)
1011
+ // {
1012
+ int id=makeNodeIdentity(nodeHandle);
1013
+ if(NULL==id) return null;
1014
+ Node newnode=(Node)m_nodes.get(id);
1015
+ String newname=newnode.getLocalName();
1016
+ if (null == newname)
1017
+ {
1018
+ // XSLT treats PIs, and possibly other things, as having QNames.
1019
+ String qname = newnode.getNodeName();
1020
+ if('#'==qname.charAt(0))
1021
+ {
1022
+ // Match old default for this function
1023
+ // This conversion may or may not be necessary
1024
+ newname="";
1025
+ }
1026
+ else
1027
+ {
1028
+ int index = qname.indexOf(':');
1029
+ newname = (index < 0) ? qname : qname.substring(index + 1);
1030
+ }
1031
+ }
1032
+ return newname;
1033
+ // }
1034
+ // else
1035
+ // {
1036
+ // String name;
1037
+ // short type = getNodeType(nodeHandle);
1038
+ // switch (type)
1039
+ // {
1040
+ // case DTM.ATTRIBUTE_NODE :
1041
+ // case DTM.ELEMENT_NODE :
1042
+ // case DTM.ENTITY_REFERENCE_NODE :
1043
+ // case DTM.NAMESPACE_NODE :
1044
+ // case DTM.PROCESSING_INSTRUCTION_NODE :
1045
+ // {
1046
+ // Node node = getNode(nodeHandle);
1047
+ //
1048
+ // // assume not null.
1049
+ // name = node.getLocalName();
1050
+ //
1051
+ // if (null == name)
1052
+ // {
1053
+ // String qname = node.getNodeName();
1054
+ // int index = qname.indexOf(':');
1055
+ //
1056
+ // name = (index < 0) ? qname : qname.substring(index + 1);
1057
+ // }
1058
+ // }
1059
+ // break;
1060
+ // default :
1061
+ // name = "";
1062
+ // }
1063
+ // return name;
1064
+ // }
1065
+ }
1066
+
1067
+ /**
1068
+ * Given a namespace handle, return the prefix that the namespace decl is
1069
+ * mapping.
1070
+ * Given a node handle, return the prefix used to map to the namespace.
1071
+ *
1072
+ * <p> %REVIEW% Are you sure you want "" for no prefix? </p>
1073
+ * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb </p>
1074
+ *
1075
+ * @param nodeHandle the id of the node.
1076
+ * @return String prefix of this node's name, or "" if no explicit
1077
+ * namespace prefix was given.
1078
+ */
1079
+ public String getPrefix(int nodeHandle)
1080
+ {
1081
+
1082
+ String prefix;
1083
+ short type = getNodeType(nodeHandle);
1084
+
1085
+ switch (type)
1086
+ {
1087
+ case DTM.NAMESPACE_NODE :
1088
+ {
1089
+ Node node = getNode(nodeHandle);
1090
+
1091
+ // assume not null.
1092
+ String qname = node.getNodeName();
1093
+ int index = qname.indexOf(':');
1094
+
1095
+ prefix = (index < 0) ? "" : qname.substring(index + 1);
1096
+ }
1097
+ break;
1098
+ case DTM.ATTRIBUTE_NODE :
1099
+ case DTM.ELEMENT_NODE :
1100
+ {
1101
+ Node node = getNode(nodeHandle);
1102
+
1103
+ // assume not null.
1104
+ String qname = node.getNodeName();
1105
+ int index = qname.indexOf(':');
1106
+
1107
+ prefix = (index < 0) ? "" : qname.substring(0, index);
1108
+ }
1109
+ break;
1110
+ default :
1111
+ prefix = "";
1112
+ }
1113
+
1114
+ return prefix;
1115
+ }
1116
+
1117
+ /**
1118
+ * Given a node handle, return its DOM-style namespace URI
1119
+ * (As defined in Namespaces, this is the declared URI which this node's
1120
+ * prefix -- or default in lieu thereof -- was mapped to.)
1121
+ *
1122
+ * <p>%REVIEW% Null or ""? -sb</p>
1123
+ *
1124
+ * @param nodeHandle the id of the node.
1125
+ * @return String URI value of this node's namespace, or null if no
1126
+ * namespace was resolved.
1127
+ */
1128
+ public String getNamespaceURI(int nodeHandle)
1129
+ {
1130
+ // if(JJK_NEWCODE)
1131
+ // {
1132
+ int id=makeNodeIdentity(nodeHandle);
1133
+ if(id==NULL) return null;
1134
+ Node node=(Node)m_nodes.get(id);
1135
+ return node.getNamespaceURI();
1136
+ // }
1137
+ // else
1138
+ // {
1139
+ // String nsuri;
1140
+ // short type = getNodeType(nodeHandle);
1141
+ //
1142
+ // switch (type)
1143
+ // {
1144
+ // case DTM.ATTRIBUTE_NODE :
1145
+ // case DTM.ELEMENT_NODE :
1146
+ // case DTM.ENTITY_REFERENCE_NODE :
1147
+ // case DTM.NAMESPACE_NODE :
1148
+ // case DTM.PROCESSING_INSTRUCTION_NODE :
1149
+ // {
1150
+ // Node node = getNode(nodeHandle);
1151
+ //
1152
+ // // assume not null.
1153
+ // nsuri = node.getNamespaceURI();
1154
+ //
1155
+ // // %TBD% Handle DOM1?
1156
+ // }
1157
+ // break;
1158
+ // default :
1159
+ // nsuri = null;
1160
+ // }
1161
+ //
1162
+ // return nsuri;
1163
+ // }
1164
+ }
1165
+
1166
+ /** Utility function: Given a DOM Text node, determine whether it is
1167
+ * logically followed by another Text or CDATASection node. This may
1168
+ * involve traversing into Entity References.
1169
+ *
1170
+ * %REVIEW% DOM Level 3 is expected to add functionality which may
1171
+ * allow us to retire this.
1172
+ */
1173
+ private Node logicalNextDOMTextNode(Node n)
1174
+ {
1175
+ Node p=n.getNextSibling();
1176
+ if(p==null)
1177
+ {
1178
+ // Walk out of any EntityReferenceNodes that ended with text
1179
+ for(n=n.getParentNode();
1180
+ n!=null && ENTITY_REFERENCE_NODE == n.getNodeType();
1181
+ n=n.getParentNode())
1182
+ {
1183
+ p=n.getNextSibling();
1184
+ if(p!=null)
1185
+ break;
1186
+ }
1187
+ }
1188
+ n=p;
1189
+ while(n!=null && ENTITY_REFERENCE_NODE == n.getNodeType())
1190
+ {
1191
+ // Walk into any EntityReferenceNodes that start with text
1192
+ if(n.hasChildNodes())
1193
+ n=n.getFirstChild();
1194
+ else
1195
+ n=n.getNextSibling();
1196
+ }
1197
+ if(n!=null)
1198
+ {
1199
+ // Found a logical next sibling. Is it text?
1200
+ int ntype=n.getNodeType();
1201
+ if(TEXT_NODE != ntype && CDATA_SECTION_NODE != ntype)
1202
+ n=null;
1203
+ }
1204
+ return n;
1205
+ }
1206
+
1207
+ /**
1208
+ * Given a node handle, return its node value. This is mostly
1209
+ * as defined by the DOM, but may ignore some conveniences.
1210
+ * <p>
1211
+ *
1212
+ * @param nodeHandle The node id.
1213
+ * @return String Value of this node, or null if not
1214
+ * meaningful for this node type.
1215
+ */
1216
+ public String getNodeValue(int nodeHandle)
1217
+ {
1218
+ // The _type(nodeHandle) call was taking the lion's share of our
1219
+ // time, and was wrong anyway since it wasn't coverting handle to
1220
+ // identity. Inlined it.
1221
+ int type = _exptype(makeNodeIdentity(nodeHandle));
1222
+ type=(NULL != type) ? getNodeType(nodeHandle) : NULL;
1223
+
1224
+ if(TEXT_NODE!=type && CDATA_SECTION_NODE!=type)
1225
+ return getNode(nodeHandle).getNodeValue();
1226
+
1227
+ // If this is a DTM text node, it may be made of multiple DOM text
1228
+ // nodes -- including navigating into Entity References. DOM2DTM
1229
+ // records the first node in the sequence and requires that we
1230
+ // pick up the others when we retrieve the DTM node's value.
1231
+ //
1232
+ // %REVIEW% DOM Level 3 is expected to add a "whole text"
1233
+ // retrieval method which performs this function for us.
1234
+ Node node = getNode(nodeHandle);
1235
+ Node n=logicalNextDOMTextNode(node);
1236
+ if(n==null)
1237
+ return node.getNodeValue();
1238
+
1239
+ FastStringBuffer buf = StringBufferPool.get();
1240
+ buf.append(node.getNodeValue());
1241
+ while(n!=null)
1242
+ {
1243
+ buf.append(n.getNodeValue());
1244
+ n=logicalNextDOMTextNode(n);
1245
+ }
1246
+ String s = (buf.length() > 0) ? buf.toString() : "";
1247
+ StringBufferPool.free(buf);
1248
+ return s;
1249
+ }
1250
+
1251
+ /**
1252
+ * A document type declaration information item has the following properties:
1253
+ *
1254
+ * 1. [system identifier] The system identifier of the external subset, if
1255
+ * it exists. Otherwise this property has no value.
1256
+ *
1257
+ * @return the system identifier String object, or null if there is none.
1258
+ */
1259
+ public String getDocumentTypeDeclarationSystemIdentifier()
1260
+ {
1261
+
1262
+ Document doc;
1263
+
1264
+ if (m_root.getNodeType() == Node.DOCUMENT_NODE)
1265
+ doc = (Document) m_root;
1266
+ else
1267
+ doc = m_root.getOwnerDocument();
1268
+
1269
+ if (null != doc)
1270
+ {
1271
+ DocumentType dtd = doc.getDoctype();
1272
+
1273
+ if (null != dtd)
1274
+ {
1275
+ return dtd.getSystemId();
1276
+ }
1277
+ }
1278
+
1279
+ return null;
1280
+ }
1281
+
1282
+ /**
1283
+ * Return the public identifier of the external subset,
1284
+ * normalized as described in 4.2.2 External Entities [XML]. If there is
1285
+ * no external subset or if it has no public identifier, this property
1286
+ * has no value.
1287
+ *
1288
+ * @return the public identifier String object, or null if there is none.
1289
+ */
1290
+ public String getDocumentTypeDeclarationPublicIdentifier()
1291
+ {
1292
+
1293
+ Document doc;
1294
+
1295
+ if (m_root.getNodeType() == Node.DOCUMENT_NODE)
1296
+ doc = (Document) m_root;
1297
+ else
1298
+ doc = m_root.getOwnerDocument();
1299
+
1300
+ if (null != doc)
1301
+ {
1302
+ DocumentType dtd = doc.getDoctype();
1303
+
1304
+ if (null != dtd)
1305
+ {
1306
+ return dtd.getPublicId();
1307
+ }
1308
+ }
1309
+
1310
+ return null;
1311
+ }
1312
+
1313
+ /**
1314
+ * Returns the <code>Element</code> whose <code>ID</code> is given by
1315
+ * <code>elementId</code>. If no such element exists, returns
1316
+ * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1317
+ * has this <code>ID</code>. Attributes (including those
1318
+ * with the name "ID") are not of type ID unless so defined by DTD/Schema
1319
+ * information available to the DTM implementation.
1320
+ * Implementations that do not know whether attributes are of type ID or
1321
+ * not are expected to return <code>DTM.NULL</code>.
1322
+ *
1323
+ * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1324
+ * and this operation searches only within a single document, right?
1325
+ * Wouldn't want collisions between DTMs in the same process.</p>
1326
+ *
1327
+ * @param elementId The unique <code>id</code> value for an element.
1328
+ * @return The handle of the matching element.
1329
+ */
1330
+ public int getElementById(String elementId)
1331
+ {
1332
+
1333
+ Document doc = (m_root.getNodeType() == Node.DOCUMENT_NODE)
1334
+ ? (Document) m_root : m_root.getOwnerDocument();
1335
+
1336
+ if(null != doc)
1337
+ {
1338
+ Node elem = doc.getElementById(elementId);
1339
+ if(null != elem)
1340
+ {
1341
+ int elemHandle = getHandleFromNode(elem);
1342
+
1343
+ if(DTM.NULL == elemHandle)
1344
+ {
1345
+ int identity = m_nodes.size()-1;
1346
+ while (DTM.NULL != (identity = getNextNodeIdentity(identity)))
1347
+ {
1348
+ Node node = getNode(identity);
1349
+ if(node == elem)
1350
+ {
1351
+ elemHandle = getHandleFromNode(elem);
1352
+ break;
1353
+ }
1354
+ }
1355
+ }
1356
+
1357
+ return elemHandle;
1358
+ }
1359
+
1360
+ }
1361
+ return DTM.NULL;
1362
+ }
1363
+
1364
+ /**
1365
+ * The getUnparsedEntityURI function returns the URI of the unparsed
1366
+ * entity with the specified name in the same document as the context
1367
+ * node (see [3.3 Unparsed Entities]). It returns the empty string if
1368
+ * there is no such entity.
1369
+ * <p>
1370
+ * XML processors may choose to use the System Identifier (if one
1371
+ * is provided) to resolve the entity, rather than the URI in the
1372
+ * Public Identifier. The details are dependent on the processor, and
1373
+ * we would have to support some form of plug-in resolver to handle
1374
+ * this properly. Currently, we simply return the System Identifier if
1375
+ * present, and hope that it a usable URI or that our caller can
1376
+ * map it to one.
1377
+ * TODO: Resolve Public Identifiers... or consider changing function name.
1378
+ * <p>
1379
+ * If we find a relative URI
1380
+ * reference, XML expects it to be resolved in terms of the base URI
1381
+ * of the document. The DOM doesn't do that for us, and it isn't
1382
+ * entirely clear whether that should be done here; currently that's
1383
+ * pushed up to a higher level of our application. (Note that DOM Level
1384
+ * 1 didn't store the document's base URI.)
1385
+ * TODO: Consider resolving Relative URIs.
1386
+ * <p>
1387
+ * (The DOM's statement that "An XML processor may choose to
1388
+ * completely expand entities before the structure model is passed
1389
+ * to the DOM" refers only to parsed entities, not unparsed, and hence
1390
+ * doesn't affect this function.)
1391
+ *
1392
+ * @param name A string containing the Entity Name of the unparsed
1393
+ * entity.
1394
+ *
1395
+ * @return String containing the URI of the Unparsed Entity, or an
1396
+ * empty string if no such entity exists.
1397
+ */
1398
+ public String getUnparsedEntityURI(String name)
1399
+ {
1400
+
1401
+ String url = "";
1402
+ Document doc = (m_root.getNodeType() == Node.DOCUMENT_NODE)
1403
+ ? (Document) m_root : m_root.getOwnerDocument();
1404
+
1405
+ if (null != doc)
1406
+ {
1407
+ DocumentType doctype = doc.getDoctype();
1408
+
1409
+ if (null != doctype)
1410
+ {
1411
+ NamedNodeMap entities = doctype.getEntities();
1412
+ if(null == entities)
1413
+ return url;
1414
+ Entity entity = (Entity) entities.getNamedItem(name);
1415
+ if(null == entity)
1416
+ return url;
1417
+
1418
+ String notationName = entity.getNotationName();
1419
+
1420
+ if (null != notationName) // then it's unparsed
1421
+ {
1422
+ // The draft says: "The XSLT processor may use the public
1423
+ // identifier to generate a URI for the entity instead of the URI
1424
+ // specified in the system identifier. If the XSLT processor does
1425
+ // not use the public identifier to generate the URI, it must use
1426
+ // the system identifier; if the system identifier is a relative
1427
+ // URI, it must be resolved into an absolute URI using the URI of
1428
+ // the resource containing the entity declaration as the base
1429
+ // URI [RFC2396]."
1430
+ // So I'm falling a bit short here.
1431
+ url = entity.getSystemId();
1432
+
1433
+ if (null == url)
1434
+ {
1435
+ url = entity.getPublicId();
1436
+ }
1437
+ else
1438
+ {
1439
+ // This should be resolved to an absolute URL, but that's hard
1440
+ // to do from here.
1441
+ }
1442
+ }
1443
+ }
1444
+ }
1445
+
1446
+ return url;
1447
+ }
1448
+
1449
+ /**
1450
+ * 5. [specified] A flag indicating whether this attribute was actually
1451
+ * specified in the start-tag of its element, or was defaulted from the
1452
+ * DTD.
1453
+ *
1454
+ * @param attributeHandle the attribute handle
1455
+ * @return <code>true</code> if the attribute was specified;
1456
+ * <code>false</code> if it was defaulted.
1457
+ */
1458
+ public boolean isAttributeSpecified(int attributeHandle)
1459
+ {
1460
+ int type = getNodeType(attributeHandle);
1461
+
1462
+ if (DTM.ATTRIBUTE_NODE == type)
1463
+ {
1464
+ Attr attr = (Attr)getNode(attributeHandle);
1465
+ return attr.getSpecified();
1466
+ }
1467
+ return false;
1468
+ }
1469
+
1470
+ /** Bind an IncrementalSAXSource to this DTM. NOT RELEVANT for DOM2DTM, since
1471
+ * we're wrapped around an existing DOM.
1472
+ *
1473
+ * @param source The IncrementalSAXSource that we want to recieve events from
1474
+ * on demand.
1475
+ */
1476
+ public void setIncrementalSAXSource(IncrementalSAXSource source)
1477
+ {
1478
+ }
1479
+
1480
+ /** getContentHandler returns "our SAX builder" -- the thing that
1481
+ * someone else should send SAX events to in order to extend this
1482
+ * DTM model.
1483
+ *
1484
+ * @return null if this model doesn't respond to SAX events,
1485
+ * "this" if the DTM object has a built-in SAX ContentHandler,
1486
+ * the IncrmentalSAXSource if we're bound to one and should receive
1487
+ * the SAX stream via it for incremental build purposes...
1488
+ * */
1489
+ public org.xml.sax.ContentHandler getContentHandler()
1490
+ {
1491
+ return null;
1492
+ }
1493
+
1494
+ /**
1495
+ * Return this DTM's lexical handler.
1496
+ *
1497
+ * %REVIEW% Should this return null if constrution already done/begun?
1498
+ *
1499
+ * @return null if this model doesn't respond to lexical SAX events,
1500
+ * "this" if the DTM object has a built-in SAX ContentHandler,
1501
+ * the IncrementalSAXSource if we're bound to one and should receive
1502
+ * the SAX stream via it for incremental build purposes...
1503
+ */
1504
+ public org.xml.sax.ext.LexicalHandler getLexicalHandler()
1505
+ {
1506
+
1507
+ return null;
1508
+ }
1509
+
1510
+
1511
+ /**
1512
+ * Return this DTM's EntityResolver.
1513
+ *
1514
+ * @return null if this model doesn't respond to SAX entity ref events.
1515
+ */
1516
+ public org.xml.sax.EntityResolver getEntityResolver()
1517
+ {
1518
+
1519
+ return null;
1520
+ }
1521
+
1522
+ /**
1523
+ * Return this DTM's DTDHandler.
1524
+ *
1525
+ * @return null if this model doesn't respond to SAX dtd events.
1526
+ */
1527
+ public org.xml.sax.DTDHandler getDTDHandler()
1528
+ {
1529
+
1530
+ return null;
1531
+ }
1532
+
1533
+ /**
1534
+ * Return this DTM's ErrorHandler.
1535
+ *
1536
+ * @return null if this model doesn't respond to SAX error events.
1537
+ */
1538
+ public org.xml.sax.ErrorHandler getErrorHandler()
1539
+ {
1540
+
1541
+ return null;
1542
+ }
1543
+
1544
+ /**
1545
+ * Return this DTM's DeclHandler.
1546
+ *
1547
+ * @return null if this model doesn't respond to SAX Decl events.
1548
+ */
1549
+ public org.xml.sax.ext.DeclHandler getDeclHandler()
1550
+ {
1551
+
1552
+ return null;
1553
+ }
1554
+
1555
+ /** @return true iff we're building this model incrementally (eg
1556
+ * we're partnered with a IncrementalSAXSource) and thus require that the
1557
+ * transformation and the parse run simultaneously. Guidance to the
1558
+ * DTMManager.
1559
+ * */
1560
+ public boolean needsTwoThreads()
1561
+ {
1562
+ return false;
1563
+ }
1564
+
1565
+ // ========== Direct SAX Dispatch, for optimization purposes ========
1566
+
1567
+ /**
1568
+ * Returns whether the specified <var>ch</var> conforms to the XML 1.0 definition
1569
+ * of whitespace. Refer to <A href="http://www.w3.org/TR/1998/REC-xml-19980210#NT-S">
1570
+ * the definition of <CODE>S</CODE></A> for details.
1571
+ * @param ch Character to check as XML whitespace.
1572
+ * @return =true if <var>ch</var> is XML whitespace; otherwise =false.
1573
+ */
1574
+ private static boolean isSpace(char ch)
1575
+ {
1576
+ return XMLCharacterRecognizer.isWhiteSpace(ch); // Take the easy way out for now.
1577
+ }
1578
+
1579
+ /**
1580
+ * Directly call the
1581
+ * characters method on the passed ContentHandler for the
1582
+ * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
1583
+ * for the definition of a node's string-value). Multiple calls to the
1584
+ * ContentHandler's characters methods may well occur for a single call to
1585
+ * this method.
1586
+ *
1587
+ * @param nodeHandle The node ID.
1588
+ * @param ch A non-null reference to a ContentHandler.
1589
+ *
1590
+ * @throws org.xml.sax.SAXException
1591
+ */
1592
+ public void dispatchCharactersEvents(
1593
+ int nodeHandle, org.xml.sax.ContentHandler ch,
1594
+ boolean normalize)
1595
+ throws org.xml.sax.SAXException
1596
+ {
1597
+ if(normalize)
1598
+ {
1599
+ XMLString str = getStringValue(nodeHandle);
1600
+ str = str.fixWhiteSpace(true, true, false);
1601
+ str.dispatchCharactersEvents(ch);
1602
+ }
1603
+ else
1604
+ {
1605
+ int type = getNodeType(nodeHandle);
1606
+ Node node = getNode(nodeHandle);
1607
+ dispatchNodeData(node, ch, 0);
1608
+ // Text coalition -- a DTM text node may represent multiple
1609
+ // DOM nodes.
1610
+ if(TEXT_NODE == type || CDATA_SECTION_NODE == type)
1611
+ {
1612
+ while( null != (node=logicalNextDOMTextNode(node)) )
1613
+ {
1614
+ dispatchNodeData(node, ch, 0);
1615
+ }
1616
+ }
1617
+ }
1618
+ }
1619
+
1620
+ /**
1621
+ * Retrieve the text content of a DOM subtree, appending it into a
1622
+ * user-supplied FastStringBuffer object. Note that attributes are
1623
+ * not considered part of the content of an element.
1624
+ * <p>
1625
+ * There are open questions regarding whitespace stripping.
1626
+ * Currently we make no special effort in that regard, since the standard
1627
+ * DOM doesn't yet provide DTD-based information to distinguish
1628
+ * whitespace-in-element-context from genuine #PCDATA. Note that we
1629
+ * should probably also consider xml:space if/when we address this.
1630
+ * DOM Level 3 may solve the problem for us.
1631
+ * <p>
1632
+ * %REVIEW% Note that as a DOM-level operation, it can be argued that this
1633
+ * routine _shouldn't_ perform any processing beyond what the DOM already
1634
+ * does, and that whitespace stripping and so on belong at the DTM level.
1635
+ * If you want a stripped DOM view, wrap DTM2DOM around DOM2DTM.
1636
+ *
1637
+ * @param node Node whose subtree is to be walked, gathering the
1638
+ * contents of all Text or CDATASection nodes.
1639
+ */
1640
+ protected static void dispatchNodeData(Node node,
1641
+ org.xml.sax.ContentHandler ch,
1642
+ int depth)
1643
+ throws org.xml.sax.SAXException
1644
+ {
1645
+
1646
+ switch (node.getNodeType())
1647
+ {
1648
+ case Node.DOCUMENT_FRAGMENT_NODE :
1649
+ case Node.DOCUMENT_NODE :
1650
+ case Node.ELEMENT_NODE :
1651
+ {
1652
+ for (Node child = node.getFirstChild(); null != child;
1653
+ child = child.getNextSibling())
1654
+ {
1655
+ dispatchNodeData(child, ch, depth+1);
1656
+ }
1657
+ }
1658
+ break;
1659
+ case Node.PROCESSING_INSTRUCTION_NODE : // %REVIEW%
1660
+ case Node.COMMENT_NODE :
1661
+ if(0 != depth)
1662
+ break;
1663
+ // NOTE: Because this operation works in the DOM space, it does _not_ attempt
1664
+ // to perform Text Coalition. That should only be done in DTM space.
1665
+ case Node.TEXT_NODE :
1666
+ case Node.CDATA_SECTION_NODE :
1667
+ case Node.ATTRIBUTE_NODE :
1668
+ String str = node.getNodeValue();
1669
+ if(ch instanceof org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler)
1670
+ {
1671
+ ((org.apache.xml.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler)ch).characters(node);
1672
+ }
1673
+ else
1674
+ {
1675
+ ch.characters(str.toCharArray(), 0, str.length());
1676
+ }
1677
+ break;
1678
+ // /* case Node.PROCESSING_INSTRUCTION_NODE :
1679
+ // // warning(XPATHErrorResources.WG_PARSING_AND_PREPARING);
1680
+ // break; */
1681
+ default :
1682
+ // ignore
1683
+ break;
1684
+ }
1685
+ }
1686
+
1687
+ TreeWalker m_walker = new TreeWalker(null);
1688
+
1689
+ /**
1690
+ * Directly create SAX parser events from a subtree.
1691
+ *
1692
+ * @param nodeHandle The node ID.
1693
+ * @param ch A non-null reference to a ContentHandler.
1694
+ *
1695
+ * @throws org.xml.sax.SAXException
1696
+ */
1697
+ public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch)
1698
+ throws org.xml.sax.SAXException
1699
+ {
1700
+ TreeWalker treeWalker = m_walker;
1701
+ ContentHandler prevCH = treeWalker.getContentHandler();
1702
+
1703
+ if(null != prevCH)
1704
+ {
1705
+ treeWalker = new TreeWalker(null);
1706
+ }
1707
+ treeWalker.setContentHandler(ch);
1708
+
1709
+ try
1710
+ {
1711
+ Node node = getNode(nodeHandle);
1712
+ treeWalker.traverseFragment(node);
1713
+ }
1714
+ finally
1715
+ {
1716
+ treeWalker.setContentHandler(null);
1717
+ }
1718
+ }
1719
+
1720
+ /**
1721
+ * For the moment all the run time properties are ignored by this
1722
+ * class.
1723
+ *
1724
+ * @param property a <code>String</code> value
1725
+ * @param value an <code>Object</code> value
1726
+ */
1727
+ public void setProperty(String property, Object value)
1728
+ {
1729
+ }
1730
+
1731
+ /**
1732
+ * No source information is available for DOM2DTM, so return
1733
+ * <code>null</code> here.
1734
+ *
1735
+ * @param node an <code>int</code> value
1736
+ * @return null
1737
+ */
1738
+ public SourceLocator getSourceLocatorFor(int node)
1739
+ {
1740
+ return null;
1741
+ }
1742
+
1743
+ }
1744
+
1745
+