dom2dtm.java
来自「JAVA 所有包」· Java 代码 · 共 1,764 行 · 第 1/4 页
JAVA
1,764 行
// Did we run out of the tree? if(next==null) { m_nextsib.setElementAt(NULL,0); m_nodesAreProcessed = true; m_pos=null; if(JJK_DEBUG) { System.out.println("***** DOM2DTM Crosscheck:"); for(int i=0;i<m_nodes.size();++i) System.out.println(i+":\t"+m_firstch.elementAt(i)+"\t"+m_nextsib.elementAt(i)); } return false; } // Text needs some special handling: // // DTM may skip whitespace. This is handled by the suppressNode flag, which // when true will keep the DTM node from being created. // // DTM only directly records the first DOM node of any logically-contiguous // sequence. The lastTextNode value will be set to the last node in the // contiguous sequence, and -- AFTER the DTM addNode -- can be used to // advance next over this whole block. Should be simpler than special-casing // the above loop for "Was the logically-preceeding sibling a text node". // // Finally, a DTM node should be considered a CDATASection only if all the // contiguous text it covers is CDATASections. The first Text should // force DTM to Text. boolean suppressNode=false; Node lastTextNode=null; nexttype=next.getNodeType(); // nexttype=pos.getNodeType(); if(TEXT_NODE == nexttype || CDATA_SECTION_NODE == nexttype) { // If filtering, initially assume we're going to suppress the node suppressNode=((null != m_wsfilter) && getShouldStripWhitespace()); // Scan logically contiguous text (siblings, plus "flattening" // of entity reference boundaries). Node n=next; while(n!=null) { lastTextNode=n; // Any Text node means DTM considers it all Text if(TEXT_NODE == n.getNodeType()) nexttype=TEXT_NODE; // Any non-whitespace in this sequence blocks whitespace // suppression suppressNode &= XMLCharacterRecognizer.isWhiteSpace(n.getNodeValue()); n=logicalNextDOMTextNode(n); } } // Special handling for PIs: Some DOMs represent the XML // Declaration as a PI. This is officially incorrect, per the DOM // spec, but is considered a "wrong but tolerable" temporary // workaround pending proper handling of these fields in DOM Level // 3. We want to recognize and reject that case. else if(PROCESSING_INSTRUCTION_NODE==nexttype) { suppressNode = (pos.getNodeName().toLowerCase().equals("xml")); } if(!suppressNode) { // Inserting next. NOTE that we force the node type; for // coalesced Text, this records CDATASections adjacent to // ordinary Text as Text. int nextindex=addNode(next,m_last_parent,m_last_kid, nexttype); m_last_kid=nextindex; if(ELEMENT_NODE == nexttype) { int attrIndex=NULL; // start with no previous sib // Process attributes _now_, rather than waiting. // Simpler control flow, makes NS cache available immediately. NamedNodeMap attrs=next.getAttributes(); int attrsize=(attrs==null) ? 0 : attrs.getLength(); if(attrsize>0) { for(int i=0;i<attrsize;++i) { // No need to force nodetype in this case; // addNode() will take care of switching it from // Attr to Namespace if necessary. attrIndex=addNode(attrs.item(i), nextindex,attrIndex,NULL); m_firstch.setElementAt(DTM.NULL,attrIndex); // If the xml: prefix is explicitly declared // we don't need to synthesize one. // // NOTE that XML Namespaces were not originally // defined as being namespace-aware (grrr), and // while the W3C is planning to fix this it's // safer for now to test the QName and trust the // parsers to prevent anyone from redefining the // reserved xmlns: prefix if(!m_processedFirstElement && "xmlns:xml".equals(attrs.item(i).getNodeName())) m_processedFirstElement=true; } // Terminate list of attrs, and make sure they aren't // considered children of the element } // if attrs exist if(!m_processedFirstElement) { // The DOM might not have an explicit declaration for the // implicit "xml:" prefix, but the XPath data model // requires that this appear as a Namespace Node so we // have to synthesize one. You can think of this as // being a default attribute defined by the XML // Namespaces spec rather than by the DTD. attrIndex=addNode(new DOM2DTMdefaultNamespaceDeclarationNode( (Element)next,"xml",NAMESPACE_DECL_NS, makeNodeHandle(((attrIndex==NULL)?nextindex:attrIndex)+1) ), nextindex,attrIndex,NULL); m_firstch.setElementAt(DTM.NULL,attrIndex); m_processedFirstElement=true; } if(attrIndex!=NULL) m_nextsib.setElementAt(DTM.NULL,attrIndex); } //if(ELEMENT_NODE) } // (if !suppressNode) // Text postprocessing: Act on values stored above if(TEXT_NODE == nexttype || CDATA_SECTION_NODE == nexttype) { // %TBD% If nexttype was forced to TEXT, patch the DTM node next=lastTextNode; // Advance the DOM cursor over contiguous text } // Remember where we left off. m_pos=next; return true; } /** * Return an DOM node for the given node. * * @param nodeHandle The node ID. * * @return A node representation of the DTM node. */ public Node getNode(int nodeHandle) { int identity = makeNodeIdentity(nodeHandle); return (Node) m_nodes.elementAt(identity); } /** * Get a Node from an identity index. * * NEEDSDOC @param nodeIdentity * * NEEDSDOC ($objectName$) @return */ protected Node lookupNode(int nodeIdentity) { return (Node) m_nodes.elementAt(nodeIdentity); } /** * Get the next node identity value in the list, and call the iterator * if it hasn't been added yet. * * @param identity The node identity (index). * @return identity+1, or DTM.NULL. */ protected int getNextNodeIdentity(int identity) { identity += 1; if (identity >= m_nodes.size()) { if (!nextNode()) identity = DTM.NULL; } return identity; } /** * Get the handle from a Node. * <p>%OPT% This will be pretty slow.</p> * * <p>%OPT% An XPath-like search (walk up DOM to root, tracking path; * walk down DTM reconstructing path) might be considerably faster * on later nodes in large documents. That might also imply improving * this call to handle nodes which would be in this DTM but * have not yet been built, which might or might not be a Good Thing.</p> * * %REVIEW% This relies on being able to test node-identity via * object-identity. DTM2DOM proxying is a great example of a case where * that doesn't work. DOM Level 3 will provide the isSameNode() method * to fix that, but until then this is going to be flaky. * * @param node A node, which may be null. * * @return The node handle or <code>DTM.NULL</code>. */ private int getHandleFromNode(Node node) { if (null != node) { int len = m_nodes.size(); boolean isMore; int i = 0; do { for (; i < len; i++) { if (m_nodes.elementAt(i) == node) return makeNodeHandle(i); } isMore = nextNode(); len = m_nodes.size(); } while(isMore || i < len); } return DTM.NULL; } /** Get the handle from a Node. This is a more robust version of * getHandleFromNode, intended to be usable by the public. * * <p>%OPT% This will be pretty slow.</p> * * %REVIEW% This relies on being able to test node-identity via * object-identity. DTM2DOM proxying is a great example of a case where * that doesn't work. DOM Level 3 will provide the isSameNode() method * to fix that, but until then this is going to be flaky. * * @param node A node, which may be null. * * @return The node handle or <code>DTM.NULL</code>. */ public int getHandleOfNode(Node node) { if (null != node) { // Is Node actually within the same document? If not, don't search! // This would be easier if m_root was always the Document node, but // we decided to allow wrapping a DTM around a subtree. if((m_root==node) || (m_root.getNodeType()==DOCUMENT_NODE && m_root==node.getOwnerDocument()) || (m_root.getNodeType()!=DOCUMENT_NODE && m_root.getOwnerDocument()==node.getOwnerDocument()) ) { // If node _is_ in m_root's tree, find its handle // // %OPT% This check may be improved significantly when DOM // Level 3 nodeKey and relative-order tests become // available! for(Node cursor=node; cursor!=null; cursor= (cursor.getNodeType()!=ATTRIBUTE_NODE) ? cursor.getParentNode() : ((org.w3c.dom.Attr)cursor).getOwnerElement()) { if(cursor==m_root) // We know this node; find its handle. return getHandleFromNode(node); } // for ancestors of node } // if node and m_root in same Document } // if node!=null return DTM.NULL; } /** * Retrieves an attribute node by by qualified name and namespace URI. * * @param nodeHandle int Handle of the node upon which to look up this attribute.. * @param namespaceURI The namespace URI of the attribute to * retrieve, or null. * @param name The local name of the attribute to * retrieve. * @return The attribute node handle with the specified name ( * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such * attribute. */ public int getAttributeNode(int nodeHandle, String namespaceURI, String name) { // %OPT% This is probably slower than it needs to be. if (null == namespaceURI) namespaceURI = ""; int type = getNodeType(nodeHandle); if (DTM.ELEMENT_NODE == type) { // Assume that attributes immediately follow the element. int identity = makeNodeIdentity(nodeHandle); while (DTM.NULL != (identity = getNextNodeIdentity(identity))) { // Assume this can not be null. type = _type(identity); // %REVIEW% // Should namespace nodes be retrievable DOM-style as attrs? // If not we need a separate function... which may be desirable // architecturally, but which is ugly from a code point of view. // (If we REALLY insist on it, this code should become a subroutine // of both -- retrieve the node, then test if the type matches // what you're looking for.) if (type == DTM.ATTRIBUTE_NODE || type==DTM.NAMESPACE_NODE) { Node node = lookupNode(identity); String nodeuri = node.getNamespaceURI(); if (null == nodeuri) nodeuri = ""; String nodelocalname = node.getLocalName(); if (nodeuri.equals(namespaceURI) && name.equals(nodelocalname)) return makeNodeHandle(identity); } else // if (DTM.NAMESPACE_NODE != type) { break; } } } return DTM.NULL; } /** * Get the string-value of a node as a String object * (see http://www.w3.org/TR/xpath#data-model * for the definition of a node's string-value). * * @param nodeHandle The node ID. * * @return A string object that represents the string-value of the given node. */ public XMLString getStringValue(int nodeHandle) { int type = getNodeType(nodeHandle); Node node = getNode(nodeHandle); // %TBD% If an element only has one text node, we should just use it // directly. if(DTM.ELEMENT_NODE == type || DTM.DOCUMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type) { FastStringBuffer buf = StringBufferPool.get(); String s; try { getNodeData(node, buf); s = (buf.length() > 0) ? buf.toString() : ""; } finally { StringBufferPool.free(buf); } return m_xstrf.newstr( s ); } else if(TEXT_NODE == type || CDATA_SECTION_NODE == type) { // If this is a DTM text node, it may be made of multiple DOM text // nodes -- including navigating into Entity References. DOM2DTM // records the first node in the sequence and requires that we // pick up the others when we retrieve the DTM node's value. // // %REVIEW% DOM Level 3 is expected to add a "whole text" // retrieval method which performs this function for us. FastStringBuffer buf = StringBufferPool.get(); while(node!=null) { buf.append(node.getNodeValue()); node=logicalNextDOMTextNode(node); } String s=(buf.length() > 0) ? buf.toString() : ""; StringBufferPool.free(buf); return m_xstrf.newstr( s ); } else return m_xstrf.newstr( node.getNodeValue() ); } /** * Determine if the string-value of a node is whitespace * * @param nodeHandle The node Handle. * * @return Return true if the given node is whitespace. */ public boolean isWhitespace(int nodeHandle) { int type = getNodeType(nodeHandle); Node node = getNode(nodeHandle); if(TEXT_NODE == type || CDATA_SECTION_NODE == type) { // If this is a DTM text node, it may be made of multiple DOM text // nodes -- including navigating into Entity References. DOM2DTM // records the first node in the sequence and requires that we // pick up the others when we retrieve the DTM node's value. // // %REVIEW% DOM Level 3 is expected to add a "whole text" // retrieval method which performs this function for us. FastStringBuffer buf = StringBufferPool.get(); while(node!=null) { buf.append(node.getNodeValue()); node=logicalNextDOMTextNode(node);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?