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