Java XML Node Parent getParentOfNode(Node node)

Here you can find the source of getParentOfNode(Node node)

Description

Obtain the XPath-model parent of a DOM node -- ownerElement for Attrs, parent for other nodes.

License

Apache License

Parameter

Parameter Description
node Node whose XPath parent we want to obtain

Exception

Parameter Description
RuntimeException if the Document has no root element.This can't arise if the Document was createdvia the DOM Level 2 factory methods, but is possible if othermechanisms were used to obtain it

Return

the parent of the node, or the ownerElement if it's an Attr node, or null if the node is an orphan.

Declaration

public static Node getParentOfNode(Node node) throws RuntimeException 

Method Source Code

//package com.java2s;
/*//from   ww w .j  a v a2  s.c  o m
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.sun.org.apache.xml.internal.res.XMLErrorResources;
import com.sun.org.apache.xml.internal.res.XMLMessages;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

public class Main {
    /**
     * Obtain the XPath-model parent of a DOM node -- ownerElement for Attrs,
     * parent for other nodes. 
     * <p>
     * Background: The DOM believes that you must be your Parent's
     * Child, and thus Attrs don't have parents. XPath said that Attrs
     * do have their owning Element as their parent. This function
     * bridges the difference, either by using the DOM Level 2 ownerElement
     * function or by using a "silly and expensive function" in Level 1
     * DOMs.
     * <p>
     * (There's some discussion of future DOMs generalizing ownerElement 
     * into ownerNode and making it work on all types of nodes. This
     * still wouldn't help the users of Level 1 or Level 2 DOMs)
     * <p>
     *
     * @param node Node whose XPath parent we want to obtain
     *
     * @return the parent of the node, or the ownerElement if it's an
     * Attr node, or null if the node is an orphan.
     *
     * @throws RuntimeException if the Document has no root element.
     * This can't arise if the Document was created
     * via the DOM Level 2 factory methods, but is possible if other
     * mechanisms were used to obtain it
     */
    public static Node getParentOfNode(Node node) throws RuntimeException {
        Node parent;
        short nodeType = node.getNodeType();

        if (Node.ATTRIBUTE_NODE == nodeType) {
            Document doc = node.getOwnerDocument();
            /*
            TBD:
            if(null == doc)
            {
            throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CHILD_HAS_NO_OWNER_DOCUMENT, null));//"Attribute child does not have an owner document!");
            }
            */

            // Given how expensive the tree walk may be, we should first ask 
            // whether this DOM can answer the question for us. The additional
            // test does slow down Level 1 DOMs slightly. DOMHelper2, which
            // is currently specialized for Xerces, assumes it can use the
            // Level 2 solution. We might want to have an intermediate stage,
            // which would assume DOM Level 2 but not assume Xerces.
            //
            // (Shouldn't have to check whether impl is null in a compliant DOM,
            // but let's be paranoid for a moment...)
            DOMImplementation impl = doc.getImplementation();
            if (impl != null && impl.hasFeature("Core", "2.0")) {
                parent = ((Attr) node).getOwnerElement();
                return parent;
            }

            // DOM Level 1 solution, as fallback. Hugely expensive. 

            Element rootElem = doc.getDocumentElement();

            if (null == rootElem) {
                throw new RuntimeException(XMLMessages
                        .createXMLMessage(XMLErrorResources.ER_CHILD_HAS_NO_OWNER_DOCUMENT_ELEMENT, null)); //"Attribute child does not have an owner document element!");
            }

            parent = locateAttrParent(rootElem, node);

        } else {
            parent = node.getParentNode();

            // if((Node.DOCUMENT_NODE != nodeType) && (null == parent))
            // {
            //   throw new RuntimeException("Child does not have parent!");
            // }
        }

        return parent;
    }

    /**
     * Support for getParentOfNode; walks a DOM tree until it finds
     * the Element which owns the Attr. This is hugely expensive, and
     * if at all possible you should use the DOM Level 2 Attr.ownerElement()
     * method instead.
     *  <p>
     * The DOM Level 1 developers expected that folks would keep track
     * of the last Element they'd seen and could recover the info from
     * that source. Obviously that doesn't work very well if the only
     * information you've been presented with is the Attr. The DOM Level 2
     * getOwnerElement() method fixes that, but only for Level 2 and
     * later DOMs.
     *
     * @param elem Element whose subtree is to be searched for this Attr
     * @param attr Attr whose owner is to be located.
     *
     * @return the first Element whose attribute list includes the provided
     * attr. In modern DOMs, this will also be the only such Element. (Early
     * DOMs had some hope that Attrs might be sharable, but this idea has
     * been abandoned.)
     */
    private static Node locateAttrParent(Element elem, Node attr) {

        Node parent = null;

        // This should only be called for Level 1 DOMs, so we don't have to
        // worry about namespace issues. In later levels, it's possible
        // for a DOM to have two Attrs with the same NodeName but
        // different namespaces, and we'd need to get getAttributeNodeNS...
        // but later levels also have Attr.getOwnerElement.
        Attr check = elem.getAttributeNode(attr.getNodeName());
        if (check == attr)
            parent = elem;

        if (null == parent) {
            for (Node node = elem.getFirstChild(); null != node; node = node.getNextSibling()) {
                if (Node.ELEMENT_NODE == node.getNodeType()) {
                    parent = locateAttrParent((Element) node, attr);

                    if (null != parent)
                        break;
                }
            }
        }

        return parent;
    }
}

Related

  1. getParentElement(Node node)
  2. getParentNamespaces(Element el)
  3. getParentNode(Node node)
  4. getParentNodeNoEx(Node node, String name)
  5. getParentOfNode(Node node)
  6. getParents(Node node)
  7. isAncestor(Node ancestor, Node node)
  8. isAncestorOf(Node ancestor, Node node)
  9. isAncestorOf(Node candidateAncestor, Node candidateSibling, boolean strict)