Java XML QName Get getElements(Node context, QName qname)

Here you can find the source of getElements(Node context, QName qname)

Description

get Elements

License

Apache License

Parameter

Parameter Description
context The root node to perform the search on.
qname The QName to search for.

Return

All direct child Elements that have the given QName.

Declaration

public static Element[] getElements(Node context, QName qname) 

Method Source Code

//package com.java2s;
/* /*from w w w  .  ja va2s  .  c  o m*/
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 java.util.ArrayList;

import java.util.List;

import javax.xml.namespace.QName;

import org.w3c.dom.Attr;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Main {
    /**
     *
     * @param context
     *        The root node to perform the search on.
     * 
     * @param qname
     *        The QName to search for.
     * 
     * @return All direct child Elements that have the given QName. 
     *
     */
    public static Element[] getElements(Node context, QName qname) {
        String name = qname.getLocalPart();
        String namespace = qname.getNamespaceURI();
        return getAllElements(context, namespace, name);
    }

    /**
     *
     * @param context
     *        The Node whose direct child Elements will be returned.
     * 
     * @return All Elements that are direct children of the given Node, 
     *         regardless of namespace URI or name. The method returns an 
     *         empty array if no children exist.
     *
     */
    public static Element[] getAllElements(Node context) {
        //
        // "*" is the DOM wildcard for "any namespace"
        //
        return getAllElements(context, "*");
    }

    /**
     * 
     *
     * @param context
     *        The Node whose direct child Elements will be returned.
     * 
     * @param namespace
     *        The namespace URI to match against all child Elements. All 
     *        returned results will have QNames with this namespace.
     * 
     * @return The set of direct child Elements whose QNames have the given 
     *         namespace URI. The method returns an empty array if there are 
     *         no children that belong the namespace.
     *
     */
    public static Element[] getAllElements(Node context, String namespace) {

        //
        // "*" is the DOM wildcard for "any name"
        //
        return getAllElements(context, namespace, "*");
    }

    /**
     * 
     * 
     *
     * @param context
     *        The Node whose direct child Elements will be returned.
     * 
     * @param namespace
     *        The namespace URI to match against all child Elements. All 
     *        returned results will have QNames with this namespace.
     * 
     * @param localName
     *        The local (non-prefixed) name to match against all child 
     *        Elements. All returned results will have QNames with this name.
     * 
     * @return The set of direct child Elements whose QNames have the given 
     *         namespace URI and name. The method returns an empty array if 
     *         no children have such a QName.
     *
     */
    public static Element[] getAllElements(Node context, String namespace, String localName) {
        //
        // NOTE: The DOM API has a getElementsByTagName feature that allows 
        // for wild cards. Unfortunately, this function returns ALL matches 
        // in the XML sub-tree. so, given the following:
        //
        // <?xml version="1.0"?>
        // <TypeA>
        //   <TypeB>
        //     <TypeC>
        //       <TypeD/>
        //     </TypeC>
        //   </TypeB>
        //   <TypeD/>
        // </TypeA>
        //
        // If TypeA is the context node, and TypeD is the element 
        // name we are searching against, the DOM API will return 
        // both of the TypeD elements in the document, even though 
        // only one of them is a direct child of TypeA.
        //
        // The getAllElements method is supposed to return all of 
        // the elements that are direct children of the context node. 
        // rather than taking the results of getElementsByTagName 
        // and filtering them based on their parent node, this 
        // implementation takes the search into its own hands; because 
        // we are only comparing the direct children, this should be 
        // much faster for large XML trees.
        //

        boolean matchAllNames = localName.equals("*");
        boolean matchAllNamespaces = namespace.equals("*");

        NodeList children = context.getChildNodes();
        int totalLength = children.getLength();

        List elements = new ArrayList(totalLength);

        for (int n = 0; n < totalLength; ++n) {
            //
            // the context root may have child nodes that are not 
            // Elements, so we have to check
            //
            Node next = children.item(n);

            //
            // first check - is it an Element?
            //
            if (next.getNodeType() != Node.ELEMENT_NODE)
                continue;

            String nextName = next.getLocalName();
            String nextNamespace = next.getNamespaceURI();

            //
            // check if it's DOM Level 1 (no NS concept). we have to 
            // skip Level 1 nodes unless we're matching all NSs
            //
            if (nextNamespace == null) {
                if (!matchAllNamespaces)
                    continue;

                nextName = next.getNodeName();
            }

            //
            // second check - do the namespaces match?
            //
            // NOTE: this will pass for DOM Level 1 if we are matching 
            //       all namespaces
            //
            if ((matchAllNamespaces || namespace.equals(nextNamespace))
                    && (matchAllNames || localName.equals(nextName)))
                elements.add(next);
        }

        Element[] resultsAsArray = new Element[elements.size()];
        return (Element[]) elements.toArray(resultsAsArray);
    }

    /**
     *
     * @param e1
     * @param e2
     * 
     * @return True, if:
     *         <ul>
     *         <li>The two Elements have the same QName.</li>
     *         <li>They have the same child elements, <b>in the same 
     *         order</b>; this includes Elements and Texts.</li>
     *         <li>They have the same attributes, excluding XML namespace 
     *         and prefix definitions.</li>
     *         </ul>
     *         This method short-circuits to "true" if the two references 
     *         are the same (e1 == e2). It short-circuits to "false" if 
     *         one reference is null and the other isn't.
     * 
     */
    public static boolean equals(Element e1, Element e2) {
        //
        // avoid semantic comparisons if we can
        //
        if (e1 == e2)
            return true;

        //
        // they're not the same reference, so if either equals null, 
        // we can quit
        //
        if (e1 == null || e2 == null)
            return false;

        //
        // make sure root elements are the same, including tag name
        //
        QName qname1 = getElementQName(e1);
        QName qname2 = getElementQName(e2);

        if (!qname1.equals(qname2))
            return false;

        return haveMatchingChildren(e1, e2) && haveMatchingAttributes(e1, e2);
    }

    /**
     * 
     * @param xml
     *        The Element whose QName will be returned.
     * 
     * @return The QName of the given Element definition.
     *
     */
    public static QName getElementQName(Element xml) {
        String uri = xml.getNamespaceURI();
        String prefix = xml.getPrefix();
        String name = xml.getLocalName();

        //
        // support for DOM Level 1 - no NS concept
        //
        if (name == null)
            return new QName(xml.getNodeName());

        //
        // prefix is not required, but it CANNOT be null
        //
        if (prefix != null && prefix.length() > 0)
            return new QName(uri, name, prefix);

        return new QName(uri, name);
    }

    /**
     *
     * Recursively compares the children in the Element sub-trees to see if 
     * they are of equal name, value, and <b>order</b>. Only Element and 
     * Text nodes are compared.
     * 
     * @param e1
     * @param e2
     * 
     * @return True if the two Elements have the same children, in the same 
     *         order. The comparison only targets Element and Text children, 
     *         not Attr or other DOM Nodes.
     * 
     * @see #haveMatchingAttributes(Element, Element)
     *
     */
    public static boolean haveMatchingChildren(Element e1, Element e2) {
        //
        // compare all the child nodes... (w/o attributes). nodes must be 
        // identical and IN THE SAME ORDER - if this is so, the node types 
        // should match
        //

        NodeList children1 = e1.getChildNodes();
        NodeList children2 = e2.getChildNodes();

        int length1 = children1.getLength();
        int length2 = children2.getLength();

        if (length1 != length2)
            return false;

        for (int n = 0; n < length1; ++n) {
            Node next1 = children1.item(n);
            Node next2 = children2.item(n);

            short type1 = next1.getNodeType();
            short type2 = next2.getNodeType();

            //
            // nodes aren't the same type - WRONG ORDER!
            //
            if (type1 != type2)
                return false;

            //
            // only concerned with Text and Element nodes - Comments and 
            // CDATA are ignored
            //

            else if (type1 == Node.TEXT_NODE) {
                String text1 = next1.getNodeValue();
                String text2 = next2.getNodeValue();

                if (!text1.equals(text2))
                    return false;
            }

            //
            // recurse down the tree to do more comparisons
            //
            else if (type1 == Node.ELEMENT_NODE && !equals((Element) next1, (Element) next2))
                return false;
        }

        return true;
    }

    /**
     * 
     * @param e1
     * @param e2
     * 
     * @return True if the two Elements have the same attributes and 
     *         attribute values. The comparison <b>excludes</b> XML 
     *         namespace declarations, since the prefixes used in an 
     *         XML fragment are not important. 
     *
     */
    public static boolean haveMatchingAttributes(Element e1, Element e2) {
        //
        // the order of the attributes is not important, just the values. 
        // we ignore namespace URI attributes because the prefixes used 
        // in a fragment are also unimportant
        //

        NamedNodeMap attr1 = e1.getAttributes();
        NamedNodeMap attr2 = e2.getAttributes();

        int length1 = attr1.getLength();
        int length2 = attr2.getLength();

        NamedNodeMap larger = length1 >= length2 ? attr1 : attr2;
        int largerLength = larger.getLength();

        for (int n = 0; n < largerLength; ++n) {
            Attr attr = (Attr) larger.item(n);
            String name = attr.getName();
            String value = attr.getValue();

            //
            // ignore namespace URI declarations...
            //
            if (!name.startsWith("xmlns:")) {
                Attr match = (Attr) larger.getNamedItem(name);

                if (match == null)
                    return false;

                String matchValue = match.getValue();

                if (matchValue == null || !matchValue.equals(value))
                    return false;
            }
        }

        return true;
    }
}

Related

  1. getElementQName(Class type)
  2. getElementQName(Element element)
  3. getElementQName(Element xml)
  4. getElementQName(final Element el)
  5. getName(QName qName)
  6. getName(QName qname)
  7. getQName(@Nonnull final Element aElement)
  8. getQName(Class klass)