19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/* 29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one 39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file 49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information 59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file 69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the "License"); 79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License. 89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at 99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software 139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and 169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License. 179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/* 199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: DOMHelper.java 468655 2006-10-28 07:12:06Z minchau $ 209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xml.utils; 229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Hashtable; 249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Vector; 259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport javax.xml.XMLConstants; 279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport javax.xml.parsers.DocumentBuilder; 289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport javax.xml.parsers.DocumentBuilderFactory; 299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport javax.xml.parsers.ParserConfigurationException; 309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.dtm.ref.DTMNodeProxy; 329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.res.XMLErrorResources; 339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.res.XMLMessages; 349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.Attr; 369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.DOMImplementation; 379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.Document; 389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.DocumentType; 399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.Element; 409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.Entity; 419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.NamedNodeMap; 429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.Node; 439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.w3c.dom.Text; 449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/** 469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @deprecated Since the introduction of the DTM, this class will be removed. 479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class provides a front-end to DOM implementations, providing 489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * a number of utility functions that either aren't yet standardized 499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * by the DOM spec or that are defined in optional DOM modules and 509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * hence may not be present in all DOMs. 519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpublic class DOMHelper 539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{ 549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOM Level 1 did not have a standard mechanism for creating a new 579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Document object. This function provides a DOM-implementation-independent 589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * abstraction for that for that concept. It's typically used when 599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * outputting a new DOM as the result of an operation. 609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: This isn't directly compatable with DOM Level 2. 629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * The Level 2 createDocument call also creates the root 639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * element, and thus requires that you know what that element will be 649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * before creating the Document. We should think about whether we want 659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to change this code, and the callers, so we can use the DOM's own 669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * method. (It's also possible that DOM Level 3 may relax this 679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * sequence, but you may give up some intelligence in the DOM by 689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * doing so; the intent was that knowing the document type and root 699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * element might let the DOM automatically switch to a specialized 709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * subclass for particular kinds of documents.) 719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param isSecureProcessing state of the secure processing feature. 739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return The newly created DOM Document object, with no children, or 749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * null if we can't find a DOM implementation that permits creating 759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * new empty Documents. 769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static Document createDocument(boolean isSecureProcessing) 789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson try 819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Use an implementation of the JAVA API for XML Parsing 1.0 to 849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // create a DOM Document node to contain the result. 859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson dfactory.setNamespaceAware(true); 889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // BEGIN android-removed 899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // If set, DocumentBuilderFactoryImpl.newDocumentBuilder() fails 909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // because we haven't implemented validation 919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // dfactory.setValidating(true); 929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // BEGIN android-removed 939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // BEGIN android-removed 959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // We haven't implemented secure processing 969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // if (isSecureProcessing) 979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // { 989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // try 999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // { 1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); 1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // } 1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // catch (ParserConfigurationException pce) {} 1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // } 1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // END android-removed 1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); 1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Document outNode = docBuilder.newDocument(); 1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return outNode; 1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson catch (ParserConfigurationException pce) 1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson throw new RuntimeException( 1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson XMLMessages.createXMLMessage( 1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson XMLErrorResources.ER_CREATEDOCUMENT_NOT_SUPPORTED, null)); //"createDocument() not supported in XPathContext!"); 1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // return null; 1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOM Level 1 did not have a standard mechanism for creating a new 1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Document object. This function provides a DOM-implementation-independent 1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * abstraction for that for that concept. It's typically used when 1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * outputting a new DOM as the result of an operation. 1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return The newly created DOM Document object, with no children, or 1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * null if we can't find a DOM implementation that permits creating 1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * new empty Documents. 1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static Document createDocument() 1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return createDocument(false); 1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Tells, through the combination of the default-space attribute 1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * on xsl:stylesheet, xsl:strip-space, xsl:preserve-space, and the 1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * xml:space attribute, whether or not extra whitespace should be stripped 1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * from the node. Literal elements from template elements should 1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <em>not</em> be tested with this function. 1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param textNode A text node from the source tree. 1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return true if the text node should be stripped of extra whitespace. 1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @throws javax.xml.transform.TransformerException 1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @xsl.usage advanced 1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public boolean shouldStripSourceNode(Node textNode) 1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson throws javax.xml.transform.TransformerException 1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // return (null == m_envSupport) ? false : m_envSupport.shouldStripSourceNode(textNode); 1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return false; 1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Supports the XPath function GenerateID by returning a unique 1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * identifier string for any given DOM Node. 1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Warning: The base implementation uses the Node object's hashCode(), 1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * which is NOT guaranteed to be unique. If that method hasn't been 1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * overridden in this DOM ipmlementation, most Java implementions will 1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * derive it from the object's address and should be OK... but if 1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * your DOM uses a different definition of hashCode (eg hashing the 1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * contents of the subtree), or if your DOM may have multiple objects 1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * that represent a single Node in the data structure (eg via proxying), 1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may need to find another way to assign a unique identifier. 1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Also, be aware that if nodes are destroyed and recreated, there is 1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * an open issue regarding whether an ID may be reused. Currently 1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * we're assuming that the input document is stable for the duration 1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * of the XPath/XSLT operation, so this shouldn't arise in this context. 1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * (DOM Level 3 is investigating providing a unique node "key", but 1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * that won't help Level 1 and Level 2 implementations.) 1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node whose identifier you want to obtain 1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return a string which should be different for every Node object. 1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getUniqueID(Node node) 1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return "N" + Integer.toHexString(node.hashCode()).toUpperCase(); 1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Figure out whether node2 should be considered as being later 1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in the document than node1, in Document Order as defined 1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * by the XPath model. This may not agree with the ordering defined 1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * by other XML applications. 1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * There are some cases where ordering isn't defined, and neither are 1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the results of this function -- though we'll generally return true. 1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: Make sure this does the right thing with attribute nodes!!! 1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node1 DOM Node to perform position comparison on. 1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node2 DOM Node to perform position comparison on . 1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return false if node2 comes before node1, otherwise return true. 2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You can think of this as 2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <code>(node1.documentOrderPosition <= node2.documentOrderPosition)</code>. 2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static boolean isNodeAfter(Node node1, Node node2) 2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (node1 == node2 || isNodeTheSame(node1, node2)) 2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return true; 2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Default return value, if there is no defined ordering 2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean isNodeAfter = true; 2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node parent1 = getParentOfNode(node1); 2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node parent2 = getParentOfNode(node2); 2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Optimize for most common case 2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (parent1 == parent2 || isNodeTheSame(parent1, parent2)) // then we know they are siblings 2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null != parent1) 2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfter = isNodeAfterSibling(parent1, node1, node2); 2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // If both parents are null, ordering is not defined. 2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // We're returning a value in lieu of throwing an exception. 2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Not a case we expect to arise in XPath, but beware if you 2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // try to reuse this method. 2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // We can just fall through in this case, which allows us 2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // to hit the debugging code at the end of the function. 2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson //return isNodeAfter; 2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // General strategy: Figure out the lengths of the two 2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // ancestor chains, reconcile the lengths, and look for 2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the lowest common ancestor. If that ancestor is one of 2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the nodes being compared, it comes before the other. 2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Otherwise perform a sibling compare. 2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // 2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // NOTE: If no common ancestor is found, ordering is undefined 2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // and we return the default value of isNodeAfter. 2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Count parents in each ancestor chain 2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int nParents1 = 2, nParents2 = 2; // include node & parent obtained above 2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while (parent1 != null) 2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nParents1++; 2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent1 = getParentOfNode(parent1); 2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while (parent2 != null) 2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nParents2++; 2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent2 = getParentOfNode(parent2); 2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Initially assume scan for common ancestor starts with 2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the input nodes. 2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node startNode1 = node1, startNode2 = node2; 2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // If one ancestor chain is longer, adjust its start point 2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // so we're comparing at the same depths 2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (nParents1 < nParents2) 2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Adjust startNode2 to depth of startNode1 2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int adjust = nParents2 - nParents1; 2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (int i = 0; i < adjust; i++) 2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson startNode2 = getParentOfNode(startNode2); 2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if (nParents1 > nParents2) 2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // adjust startNode1 to depth of startNode2 2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int adjust = nParents1 - nParents2; 2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (int i = 0; i < adjust; i++) 2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson startNode1 = getParentOfNode(startNode1); 2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node prevChild1 = null, prevChild2 = null; // so we can "back up" 2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Loop up the ancestor chain looking for common parent 2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while (null != startNode1) 2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (startNode1 == startNode2 || isNodeTheSame(startNode1, startNode2)) // common parent? 2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null == prevChild1) // first time in loop? 2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Edge condition: one is the ancestor of the other. 2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfter = (nParents1 < nParents2) ? true : false; 3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; // from while loop 3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Compare ancestors below lowest-common as siblings 3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfter = isNodeAfterSibling(startNode1, prevChild1, 3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson prevChild2); 3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; // from while loop 3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } // end if(startNode1 == startNode2) 3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Move up one level and try again 3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson prevChild1 = startNode1; 3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson startNode1 = getParentOfNode(startNode1); 3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson prevChild2 = startNode2; 3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson startNode2 = getParentOfNode(startNode2); 3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } // end while(parents exist to examine) 3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } // end big else (not immediate siblings) 3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // WARNING: The following diagnostic won't report the early 3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // "same node" case. Fix if/when needed. 3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /* -- please do not remove... very useful for diagnostics -- 3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson System.out.println("node1 = "+node1.getNodeName()+"("+node1.getNodeType()+")"+ 3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ", node2 = "+node2.getNodeName() 3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson +"("+node2.getNodeType()+")"+ 3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ", isNodeAfter = "+isNodeAfter); */ 3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return isNodeAfter; 3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } // end isNodeAfter(Node node1, Node node2) 3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Use DTMNodeProxy to determine whether two nodes are the same. 3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node1 The first DOM node to compare. 3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node2 The second DOM node to compare. 3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return true if the two nodes are the same. 3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static boolean isNodeTheSame(Node node1, Node node2) 3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (node1 instanceof DTMNodeProxy && node2 instanceof DTMNodeProxy) 3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return ((DTMNodeProxy)node1).equals((DTMNodeProxy)node2); 3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (node1 == node2); 3459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 3469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 3489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Figure out if child2 is after child1 in document order. 3499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 3509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Warning: Some aspects of "document order" are not well defined. 3519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * For example, the order of attributes is considered 3529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * meaningless in XML, and the order reported by our model will 3539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * be consistant for a given invocation but may not 3549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * match that of either the source file or the serialized output. 3559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 3569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param parent Must be the parent of both child1 and child2. 3579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param child1 Must be the child of parent and not equal to child2. 3589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param child2 Must be the child of parent and not equal to child1. 3599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return true if child 2 is after child1 in document order. 3609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 3619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson private static boolean isNodeAfterSibling(Node parent, Node child1, 3629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node child2) 3639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean isNodeAfterSibling = false; 3669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson short child1type = child1.getNodeType(); 3679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson short child2type = child2.getNodeType(); 3689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if ((Node.ATTRIBUTE_NODE != child1type) 3709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson && (Node.ATTRIBUTE_NODE == child2type)) 3719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // always sort attributes before non-attributes. 3749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfterSibling = false; 3759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 3769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if ((Node.ATTRIBUTE_NODE == child1type) 3779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson && (Node.ATTRIBUTE_NODE != child2type)) 3789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // always sort attributes before non-attributes. 3819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfterSibling = true; 3829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 3839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if (Node.ATTRIBUTE_NODE == child1type) 3849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson NamedNodeMap children = parent.getAttributes(); 3869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int nNodes = children.getLength(); 3879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean found1 = false, found2 = false; 3889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Count from the start until we find one or the other. 3909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (int i = 0; i < nNodes; i++) 3919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node child = children.item(i); 3939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 3949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (child1 == child || isNodeTheSame(child1, child)) 3959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (found2) 3979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 3989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfterSibling = false; 3999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 4019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson found1 = true; 4049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if (child2 == child || isNodeTheSame(child2, child)) 4069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (found1) 4089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfterSibling = true; 4109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 4129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson found2 = true; 4159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 4199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // TODO: Check performance of alternate solution: 4219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // There are two choices here: Count from the start of 4229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the document until we find one or the other, or count 4239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // from one until we find or fail to find the other. 4249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Either can wind up scanning all the siblings in the worst 4259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // case, which on a wide document can be a lot of work but 4269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // is more typically is a short list. 4279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Scanning from the start involves two tests per iteration, 4289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // but it isn't clear that scanning from the middle doesn't 4299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // yield more iterations on average. 4309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // We should run some testcases. 4319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node child = parent.getFirstChild(); 4329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean found1 = false, found2 = false; 4339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while (null != child) 4359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Node child = children.item(i); 4389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (child1 == child || isNodeTheSame(child1, child)) 4399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (found2) 4419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfterSibling = false; 4439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 4459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson found1 = true; 4489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if (child2 == child || isNodeTheSame(child2, child)) 4509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (found1) 4529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson isNodeAfterSibling = true; 4549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 4569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson found2 = true; 4599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson child = child.getNextSibling(); 4629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return isNodeAfterSibling; 4669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } // end isNodeAfterSibling(Node parent, Node child1, Node child2) 4679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson //========================================================== 4699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // SECTION: Namespace resolution 4709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson //========================================================== 4719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 4739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Get the depth level of this node in the tree (equals 1 for 4749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * a parentless node). 4759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 4769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param n Node to be examined. 4779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return the number of ancestors, plus one 4789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @xsl.usage internal 4799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 4809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public short getLevel(Node n) 4819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson short level = 1; 4849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while (null != (n = getParentOfNode(n))) 4869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 4879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson level++; 4889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return level; 4919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 4929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 4939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 4949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Given an XML Namespace prefix and a context in which the prefix 4959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * is to be evaluated, return the Namespace Name this prefix was 4969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * bound to. Note that DOM Level 3 is expected to provide a version of 4979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * this which deals with the DOM's "early binding" behavior. 4989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 4999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Default handling: 5009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 5019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param prefix String containing namespace prefix to be resolved, 5029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * without the ':' which separates it from the localname when used 5039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in a Node Name. The empty sting signifies the default namespace 5049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * at this point in the document. 5059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param namespaceContext Element which provides context for resolution. 5069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * (We could extend this to work for other nodes by first seeking their 5079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * nearest Element ancestor.) 5089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 5099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return a String containing the Namespace URI which this prefix 5109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * represents in the specified context. 5119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 5129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getNamespaceForPrefix(String prefix, Element namespaceContext) 5139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int type; 5169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node parent = namespaceContext; 5179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String namespace = null; 5189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (prefix.equals("xml")) 5209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespace = QName.S_XMLNAMESPACEURI; // Hardcoded, per Namespace spec 5229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if(prefix.equals("xmlns")) 5249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Hardcoded in the DOM spec, expected to be adopted by 5269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Namespace spec. NOTE: Namespace declarations _must_ use 5279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the xmlns: prefix; other prefixes declared as belonging 5289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // to this namespace will not be recognized and should 5299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // probably be rejected by parsers as erroneous declarations. 5309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespace = "http://www.w3.org/2000/xmlns/"; 5319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 5339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Attribute name for this prefix's declaration 5359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String declname=(prefix=="") 5369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ? "xmlns" 5379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson : "xmlns:"+prefix; 5389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Scan until we run out of Elements or have resolved the namespace 5409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while ((null != parent) && (null == namespace) 5419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson && (((type = parent.getNodeType()) == Node.ELEMENT_NODE) 5429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson || (type == Node.ENTITY_REFERENCE_NODE))) 5439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (type == Node.ELEMENT_NODE) 5459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Look for the appropriate Namespace Declaration attribute, 5489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // either "xmlns:prefix" or (if prefix is "") "xmlns". 5499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // TODO: This does not handle "implicit declarations" 5509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // which may be created when the DOM is edited. DOM Level 5519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // 3 will define how those should be interpreted. But 5529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // this issue won't arise in freshly-parsed DOMs. 5539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // NOTE: declname is set earlier, outside the loop. 5559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Attr attr=((Element)parent).getAttributeNode(declname); 5569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if(attr!=null) 5579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 5589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespace = attr.getNodeValue(); 5599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 5609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = getParentOfNode(parent); 5649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return namespace; 5689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 5699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 5719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * An experiment for the moment. 5729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 5739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Hashtable m_NSInfos = new Hashtable(); 5749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Object to put into the m_NSInfos table that tells that a node has not been 5769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed, but has xmlns namespace decls. */ 5779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected static final NSInfo m_NSInfoUnProcWithXMLNS = new NSInfo(false, 5789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson true); 5799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Object to put into the m_NSInfos table that tells that a node has not been 5819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed, but has no xmlns namespace decls. */ 5829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected static final NSInfo m_NSInfoUnProcWithoutXMLNS = new NSInfo(false, 5839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson false); 5849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Object to put into the m_NSInfos table that tells that a node has not been 5869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed, and has no xmlns namespace decls, and has no ancestor decls. */ 5879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected static final NSInfo m_NSInfoUnProcNoAncestorXMLNS = 5889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson new NSInfo(false, false, NSInfo.ANCESTORNOXMLNS); 5899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Object to put into the m_NSInfos table that tells that a node has been 5919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed, and has xmlns namespace decls. */ 5929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected static final NSInfo m_NSInfoNullWithXMLNS = new NSInfo(true, 5939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson true); 5949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 5959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Object to put into the m_NSInfos table that tells that a node has been 5969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed, and has no xmlns namespace decls. */ 5979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected static final NSInfo m_NSInfoNullWithoutXMLNS = new NSInfo(true, 5989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson false); 5999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Object to put into the m_NSInfos table that tells that a node has been 6019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * processed, and has no xmlns namespace decls. and has no ancestor decls. */ 6029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected static final NSInfo m_NSInfoNullNoAncestorXMLNS = 6039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson new NSInfo(true, false, NSInfo.ANCESTORNOXMLNS); 6049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** Vector of node (odd indexes) and NSInfos (even indexes) that tell if 6069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the given node is a candidate for ancestor namespace processing. */ 6079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected Vector m_candidateNoAncestorXMLNS = new Vector(); 6089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 6109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Returns the namespace of the given node. Differs from simply getting 6119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the node's prefix and using getNamespaceForPrefix in that it attempts 6129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to cache some of the data in NSINFO objects, to avoid repeated lookup. 6139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: Should we consider moving that logic into getNamespaceForPrefix? 6149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 6159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param n Node to be examined. 6169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 6179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return String containing the Namespace Name (uri) for this node. 6189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Note that this is undefined for any nodes other than Elements and 6199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Attributes. 6209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 6219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getNamespaceOfNode(Node n) 6229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String namespaceOfPrefix; 6259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean hasProcessedNS; 6269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson NSInfo nsInfo; 6279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson short ntype = n.getNodeType(); 6289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ATTRIBUTE_NODE != ntype) 6309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Object nsObj = m_NSInfos.get(n); // return value 6329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nsInfo = (nsObj == null) ? null : (NSInfo) nsObj; 6349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson hasProcessedNS = (nsInfo == null) ? false : nsInfo.m_hasProcessedNS; 6359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 6379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson hasProcessedNS = false; 6399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nsInfo = null; 6409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (hasProcessedNS) 6439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespaceOfPrefix = nsInfo.m_namespace; 6459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 6479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespaceOfPrefix = null; 6499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String nodeName = n.getNodeName(); 6519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int indexOfNSSep = nodeName.indexOf(':'); 6529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String prefix; 6539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ATTRIBUTE_NODE == ntype) 6559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (indexOfNSSep > 0) 6579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson prefix = nodeName.substring(0, indexOfNSSep); 6599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 6619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Attributes don't use the default namespace, so if 6649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // there isn't a prefix, we're done. 6659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return namespaceOfPrefix; 6669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 6699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson prefix = (indexOfNSSep >= 0) 6719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ? nodeName.substring(0, indexOfNSSep) : ""; 6729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean ancestorsHaveXMLNS = false; 6759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean nHasXMLNS = false; 6769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (prefix.equals("xml")) 6789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespaceOfPrefix = QName.S_XMLNAMESPACEURI; 6809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 6829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int parentType; 6849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node parent = n; 6859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while ((null != parent) && (null == namespaceOfPrefix)) 6879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if ((null != nsInfo) 6899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson && (nsInfo.m_ancestorHasXMLNSAttrs 6909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson == NSInfo.ANCESTORNOXMLNS)) 6919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 6939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 6949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parentType = parent.getNodeType(); 6969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 6979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if ((null == nsInfo) || nsInfo.m_hasXMLNSAttrs) 6989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 6999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean elementHasXMLNS = false; 7009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (parentType == Node.ELEMENT_NODE) 7029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson NamedNodeMap nnm = parent.getAttributes(); 7049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (int i = 0; i < nnm.getLength(); i++) 7069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node attr = nnm.item(i); 7089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String aname = attr.getNodeName(); 7099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (aname.charAt(0) == 'x') 7119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean isPrefix = aname.startsWith("xmlns:"); 7139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (aname.equals("xmlns") || isPrefix) 7159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (n == parent) 7179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nHasXMLNS = true; 7189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson elementHasXMLNS = true; 7209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ancestorsHaveXMLNS = true; 7219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String p = isPrefix ? aname.substring(6) : ""; 7239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (p.equals(prefix)) 7259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson namespaceOfPrefix = attr.getNodeValue(); 7279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 7299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if ((Node.ATTRIBUTE_NODE != parentType) && (null == nsInfo) 7369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson && (n != parent)) 7379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nsInfo = elementHasXMLNS 7399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ? m_NSInfoUnProcWithXMLNS : m_NSInfoUnProcWithoutXMLNS; 7409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(parent, nsInfo); 7429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ATTRIBUTE_NODE == parentType) 7469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = getParentOfNode(parent); 7489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 7509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_candidateNoAncestorXMLNS.addElement(parent); 7529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_candidateNoAncestorXMLNS.addElement(nsInfo); 7539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = parent.getParentNode(); 7559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null != parent) 7589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Object nsObj = m_NSInfos.get(parent); // return value 7609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson nsInfo = (nsObj == null) ? null : (NSInfo) nsObj; 7629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int nCandidates = m_candidateNoAncestorXMLNS.size(); 7669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (nCandidates > 0) 7689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if ((false == ancestorsHaveXMLNS) && (null == parent)) 7709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (int i = 0; i < nCandidates; i += 2) 7729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Object candidateInfo = m_candidateNoAncestorXMLNS.elementAt(i 7749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson + 1); 7759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (candidateInfo == m_NSInfoUnProcWithoutXMLNS) 7779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(m_candidateNoAncestorXMLNS.elementAt(i), 7799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfoUnProcNoAncestorXMLNS); 7809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else if (candidateInfo == m_NSInfoNullWithoutXMLNS) 7829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(m_candidateNoAncestorXMLNS.elementAt(i), 7849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfoNullNoAncestorXMLNS); 7859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_candidateNoAncestorXMLNS.removeAllElements(); 7909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 7929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 7939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ATTRIBUTE_NODE != ntype) 7949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null == namespaceOfPrefix) 7969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (ancestorsHaveXMLNS) 7989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 7999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (nHasXMLNS) 8009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(n, m_NSInfoNullWithXMLNS); 8019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 8029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(n, m_NSInfoNullWithoutXMLNS); 8039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 8059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 8069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(n, m_NSInfoNullNoAncestorXMLNS); 8079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 8109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 8119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson m_NSInfos.put(n, new NSInfo(namespaceOfPrefix, nHasXMLNS)); 8129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return namespaceOfPrefix; 8179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 8209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Returns the local name of the given node. If the node's name begins 8219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * with a namespace prefix, this is the part after the colon; otherwise 8229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * it's the full node name. 8239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param n the node to be examined. 8259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return String containing the Local Name 8279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 8289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getLocalNameOfNode(Node n) 8299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 8309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String qname = n.getNodeName(); 8329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int index = qname.indexOf(':'); 8339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (index < 0) ? qname : qname.substring(index + 1); 8359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 8389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Returns the element name with the namespace prefix (if any) replaced 8399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * by the Namespace URI it was bound to. This is not a standard 8409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * representation of a node name, but it allows convenient 8419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * single-string comparison of the "universal" names of two nodes. 8429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param elem Element to be examined. 8449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return String in the form "namespaceURI:localname" if the node 8469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * belongs to a namespace, or simply "localname" if it doesn't. 8479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @see #getExpandedAttributeName 8489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 8499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getExpandedElementName(Element elem) 8509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 8519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String namespace = getNamespaceOfNode(elem); 8539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (null != namespace) 8559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ? namespace + ":" + getLocalNameOfNode(elem) 8569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson : getLocalNameOfNode(elem); 8579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 8609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Returns the attribute name with the namespace prefix (if any) replaced 8619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * by the Namespace URI it was bound to. This is not a standard 8629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * representation of a node name, but it allows convenient 8639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * single-string comparison of the "universal" names of two nodes. 8649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param attr Attr to be examined 8669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return String in the form "namespaceURI:localname" if the node 8689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * belongs to a namespace, or simply "localname" if it doesn't. 8699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @see #getExpandedElementName 8709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 8719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getExpandedAttributeName(Attr attr) 8729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 8739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String namespace = getNamespaceOfNode(attr); 8759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (null != namespace) 8779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ? namespace + ":" + getLocalNameOfNode(attr) 8789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson : getLocalNameOfNode(attr); 8799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 8809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson //========================================================== 8829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // SECTION: DOM Helper Functions 8839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson //========================================================== 8849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 8859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 8869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Tell if the node is ignorable whitespace. Note that this can 8879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * be determined only in the context of a DTD or other Schema, 8889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * and that DOM Level 2 has nostandardized DOM API which can 8899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * return that information. 8909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @deprecated 8919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node Node to be examined 8939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 8949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return CURRENTLY HARDCODED TO FALSE, but should return true if 8959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * and only if the node is of type Text, contains only whitespace, 8969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * and does not appear as part of the #PCDATA content of an element. 8979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * (Note that determining this last may require allowing for 8989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Entity References.) 8999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 9009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public boolean isIgnorableWhitespace(Text node) 9019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 9029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson boolean isIgnorable = false; // return value 9049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // TODO: I can probably do something to figure out if this 9069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // space is ignorable from just the information in 9079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the DOM tree. 9089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // -- You need to be able to distinguish whitespace 9099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // that is #PCDATA from whitespace that isn't. That requires 9109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // DTD support, which won't be standardized until DOM Level 3. 9119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return isIgnorable; 9129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 9139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 9159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Get the first unparented node in the ancestor chain. 9169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @deprecated 9179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 9189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node Starting node, to specify which chain to chase 9199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 9209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return the topmost ancestor. 9219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 9229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public Node getRoot(Node node) 9239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 9249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node root = null; 9269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson while (node != null) 9289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 9299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson root = node; 9309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson node = getParentOfNode(node); 9319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 9329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return root; 9349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 9359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 9379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Get the root node of the document tree, regardless of 9389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * whether or not the node passed in is a document node. 9399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 9409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: This doesn't handle DocumentFragments or "orphaned" subtrees 9419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * -- it's currently returning ownerDocument even when the tree is 9429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * not actually part of the main Document tree. We should either 9439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * rewrite the description to say that it finds the Document node, 9449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or change the code to walk up the ancestor chain. 9459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 9479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param n Node to be examined 9489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 9499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return the Document node. Note that this is not the correct answer 9509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * if n was (or was a child of) a DocumentFragment or an orphaned node, 9519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * as can arise if the DOM has been edited rather than being generated 9529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * by a parser. 9539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 9549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public Node getRootNode(Node n) 9559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 9569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson int nt = n.getNodeType(); 9579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return ( (Node.DOCUMENT_NODE == nt) || (Node.DOCUMENT_FRAGMENT_NODE == nt) ) 9589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson ? n : n.getOwnerDocument(); 9599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 9609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 9629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Test whether the given node is a namespace decl node. In DOM Level 2 9639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * this can be done in a namespace-aware manner, but in Level 1 DOMs 9649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * it has to be done by testing the node name. 9659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 9669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param n Node to be examined. 9679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 9689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return boolean -- true iff the node is an Attr whose name is 9699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * "xmlns" or has the "xmlns:" prefix. 9709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 9719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public boolean isNamespaceNode(Node n) 9729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 9739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ATTRIBUTE_NODE == n.getNodeType()) 9759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 9769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String attrName = n.getNodeName(); 9779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return (attrName.startsWith("xmlns:") || attrName.equals("xmlns")); 9799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 9809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return false; 9829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 9839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 9849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 9859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Obtain the XPath-model parent of a DOM node -- ownerElement for Attrs, 9869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * parent for other nodes. 9879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 9889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Background: The DOM believes that you must be your Parent's 9899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Child, and thus Attrs don't have parents. XPath said that Attrs 9909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * do have their owning Element as their parent. This function 9919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * bridges the difference, either by using the DOM Level 2 ownerElement 9929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * function or by using a "silly and expensive function" in Level 1 9939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOMs. 9949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 9959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * (There's some discussion of future DOMs generalizing ownerElement 9969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * into ownerNode and making it work on all types of nodes. This 9979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * still wouldn't help the users of Level 1 or Level 2 DOMs) 9989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 9999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 10009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node Node whose XPath parent we want to obtain 10019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 10029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return the parent of the node, or the ownerElement if it's an 10039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Attr node, or null if the node is an orphan. 10049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 10059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @throws RuntimeException if the Document has no root element. 10069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This can't arise if the Document was created 10079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * via the DOM Level 2 factory methods, but is possible if other 10089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * mechanisms were used to obtain it 10099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 10109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static Node getParentOfNode(Node node) throws RuntimeException 10119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node parent; 10139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson short nodeType = node.getNodeType(); 10149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ATTRIBUTE_NODE == nodeType) 10169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Document doc = node.getOwnerDocument(); 10189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /* 10199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson TBD: 10209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if(null == doc) 10219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CHILD_HAS_NO_OWNER_DOCUMENT, null));//"Attribute child does not have an owner document!"); 10239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 10259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Given how expensive the tree walk may be, we should first ask 10279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // whether this DOM can answer the question for us. The additional 10289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // test does slow down Level 1 DOMs slightly. DOMHelper2, which 10299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // is currently specialized for Xerces, assumes it can use the 10309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // Level 2 solution. We might want to have an intermediate stage, 10319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // which would assume DOM Level 2 but not assume Xerces. 10329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // 10339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // (Shouldn't have to check whether impl is null in a compliant DOM, 10349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // but let's be paranoid for a moment...) 10359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DOMImplementation impl=doc.getImplementation(); 10369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if(impl!=null && impl.hasFeature("Core","2.0")) 10379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent=((Attr)node).getOwnerElement(); 10399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return parent; 10409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // DOM Level 1 solution, as fallback. Hugely expensive. 10439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Element rootElem = doc.getDocumentElement(); 10459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null == rootElem) 10479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson throw new RuntimeException( 10499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson XMLMessages.createXMLMessage( 10509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson XMLErrorResources.ER_CHILD_HAS_NO_OWNER_DOCUMENT_ELEMENT, 10519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson null)); //"Attribute child does not have an owner document element!"); 10529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = locateAttrParent(rootElem, node); 10559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 10589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = node.getParentNode(); 10609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // if((Node.DOCUMENT_NODE != nodeType) && (null == parent)) 10629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // { 10639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // throw new RuntimeException("Child does not have parent!"); 10649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // } 10659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return parent; 10689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 10719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Given an ID, return the element. This can work only if the document 10729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * is interpreted in the context of a DTD or Schema, since otherwise 10739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * we don't know which attributes are or aren't IDs. 10749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 10759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Note that DOM Level 1 had no ability to retrieve this information. 10769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOM Level 2 introduced it but does not promise that it will be 10779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * supported in all DOMs; those which can't support it will always 10789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * return null. 10799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 10809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: getElementByID is currently unimplemented. Support DOM Level 2? 10819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 10829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param id The unique identifier to be searched for. 10839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param doc The document to search within. 10849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return CURRENTLY HARDCODED TO NULL, but it should be: 10859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * The node which has this unique identifier, or null if there 10869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * is no such node or this DOM can't reliably recognize it. 10879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 10889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public Element getElementByID(String id, Document doc) 10899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 10909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return null; 10919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 10929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 10939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 10949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * The getUnparsedEntityURI function returns the URI of the unparsed 10959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * entity with the specified name in the same document as the context 10969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * node (see [3.3 Unparsed Entities]). It returns the empty string if 10979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * there is no such entity. 10989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 10999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * XML processors may choose to use the System Identifier (if one 11009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * is provided) to resolve the entity, rather than the URI in the 11019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Public Identifier. The details are dependent on the processor, and 11029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * we would have to support some form of plug-in resolver to handle 11039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * this properly. Currently, we simply return the System Identifier if 11049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * present, and hope that it a usable URI or that our caller can 11059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * map it to one. 11069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: Resolve Public Identifiers... or consider changing function name. 11079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 11089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * If we find a relative URI 11099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * reference, XML expects it to be resolved in terms of the base URI 11109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * of the document. The DOM doesn't do that for us, and it isn't 11119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * entirely clear whether that should be done here; currently that's 11129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * pushed up to a higher levelof our application. (Note that DOM Level 11139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 1 didn't store the document's base URI.) 11149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * TODO: Consider resolving Relative URIs. 11159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 11169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * (The DOM's statement that "An XML processor may choose to 11179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * completely expand entities before the structure model is passed 11189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to the DOM" refers only to parsed entities, not unparsed, and hence 11199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * doesn't affect this function.) 11209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 11219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param name A string containing the Entity Name of the unparsed 11229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * entity. 11239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param doc Document node for the document to be searched. 11249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 11259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return String containing the URI of the Unparsed Entity, or an 11269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * empty string if no such entity exists. 11279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 11289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public String getUnparsedEntityURI(String name, Document doc) 11299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 11309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String url = ""; 11329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson DocumentType doctype = doc.getDoctype(); 11339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null != doctype) 11359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 11369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson NamedNodeMap entities = doctype.getEntities(); 11379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if(null == entities) 11389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return url; 11399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Entity entity = (Entity) entities.getNamedItem(name); 11409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if(null == entity) 11419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return url; 11429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String notationName = entity.getNotationName(); 11449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null != notationName) // then it's unparsed 11469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 11479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // The draft says: "The XSLT processor may use the public 11489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // identifier to generate a URI for the entity instead of the URI 11499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // specified in the system identifier. If the XSLT processor does 11509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // not use the public identifier to generate the URI, it must use 11519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the system identifier; if the system identifier is a relative 11529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // URI, it must be resolved into an absolute URI using the URI of 11539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // the resource containing the entity declaration as the base 11549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // URI [RFC2396]." 11559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // So I'm falling a bit short here. 11569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson url = entity.getSystemId(); 11579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null == url) 11599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 11609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson url = entity.getPublicId(); 11619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 11629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson else 11639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 11649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // This should be resolved to an absolute URL, but that's hard 11659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // to do from here. 11669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 11679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 11689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 11699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return url; 11719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 11729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 11749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Support for getParentOfNode; walks a DOM tree until it finds 11759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the Element which owns the Attr. This is hugely expensive, and 11769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * if at all possible you should use the DOM Level 2 Attr.ownerElement() 11779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * method instead. 11789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 11799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * The DOM Level 1 developers expected that folks would keep track 11809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * of the last Element they'd seen and could recover the info from 11819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * that source. Obviously that doesn't work very well if the only 11829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * information you've been presented with is the Attr. The DOM Level 2 11839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * getOwnerElement() method fixes that, but only for Level 2 and 11849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * later DOMs. 11859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 11869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param elem Element whose subtree is to be searched for this Attr 11879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param attr Attr whose owner is to be located. 11889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 11899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return the first Element whose attribute list includes the provided 11909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * attr. In modern DOMs, this will also be the only such Element. (Early 11919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOMs had some hope that Attrs might be sharable, but this idea has 11929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * been abandoned.) 11939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 11949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson private static Node locateAttrParent(Element elem, Node attr) 11959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 11969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Node parent = null; 11989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 11999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // This should only be called for Level 1 DOMs, so we don't have to 12009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // worry about namespace issues. In later levels, it's possible 12019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // for a DOM to have two Attrs with the same NodeName but 12029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // different namespaces, and we'd need to get getAttributeNodeNS... 12039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // but later levels also have Attr.getOwnerElement. 12049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson Attr check=elem.getAttributeNode(attr.getNodeName()); 12059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if(check==attr) 12069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = elem; 12079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null == parent) 12099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (Node node = elem.getFirstChild(); null != node; 12119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson node = node.getNextSibling()) 12129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (Node.ELEMENT_NODE == node.getNodeType()) 12149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson parent = locateAttrParent((Element) node, attr); 12169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null != parent) 12189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 12199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return parent; 12249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 12279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * The factory object used for creating nodes 12289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in the result tree. 12299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 12309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson protected Document m_DOMFactory = null; 12319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 12339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Store the factory object required to create DOM nodes 12349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in the result tree. In fact, that's just the result tree's 12359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Document node... 12369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 12379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param domFactory The DOM Document Node within whose context 12389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * the result tree will be built. 12399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 12409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public void setDOMFactory(Document domFactory) 12419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson this.m_DOMFactory = domFactory; 12439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 12469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Retrieve the factory object required to create DOM nodes 12479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in the result tree. 12489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 12499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return The result tree's DOM Document Node. 12509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 12519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public Document getDOMFactory() 12529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson if (null == this.m_DOMFactory) 12559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson this.m_DOMFactory = createDocument(); 12579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return this.m_DOMFactory; 12609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 12639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Get the textual contents of the node. See 12649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * getNodeData(Node,FastStringBuffer) for discussion of how 12659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * whitespace nodes are handled. 12669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 12679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node DOM Node to be examined 12689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @return String containing a concatenation of all the 12699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * textual content within that node. 12709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @see #getNodeData(Node,FastStringBuffer) 12719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 12729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 12739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static String getNodeData(Node node) 12749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson FastStringBuffer buf = StringBufferPool.get(); 12779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson String s; 12789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson try 12809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson getNodeData(node, buf); 12829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson s = (buf.length() > 0) ? buf.toString() : ""; 12849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson finally 12869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 12879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson StringBufferPool.free(buf); 12889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson return s; 12919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 12929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 12939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson /** 12949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Retrieve the text content of a DOM subtree, appending it into a 12959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * user-supplied FastStringBuffer object. Note that attributes are 12969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * not considered part of the content of an element. 12979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p> 12989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * There are open questions regarding whitespace stripping. 12999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Currently we make no special effort in that regard, since the standard 13009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOM doesn't yet provide DTD-based information to distinguish 13019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * whitespace-in-element-context from genuine #PCDATA. Note that we 13029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * should probably also consider xml:space if/when we address this. 13039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * DOM Level 3 may solve the problem for us. 13049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * 13059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param node Node whose subtree is to be walked, gathering the 13069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * contents of all Text or CDATASection nodes. 13079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @param buf FastStringBuffer into which the contents of the text 13089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * nodes are to be concatenated. 13099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */ 13109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson public static void getNodeData(Node node, FastStringBuffer buf) 13119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 13129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson 13139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson switch (node.getNodeType()) 13149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 13159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.DOCUMENT_FRAGMENT_NODE : 13169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.DOCUMENT_NODE : 13179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.ELEMENT_NODE : 13189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 13199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson for (Node child = node.getFirstChild(); null != child; 13209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson child = child.getNextSibling()) 13219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson { 13229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson getNodeData(child, buf); 13239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 13249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 13259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 13269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.TEXT_NODE : 13279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.CDATA_SECTION_NODE : 13289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson buf.append(node.getNodeValue()); 13299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 13309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.ATTRIBUTE_NODE : 13319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson buf.append(node.getNodeValue()); 13329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 13339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson case Node.PROCESSING_INSTRUCTION_NODE : 13349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // warning(XPATHErrorResources.WG_PARSING_AND_PREPARING); 13359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 13369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson default : 13379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // ignore 13389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson break; 13399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 13409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson } 13419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson} 1342