Here you can find the source of getElements(Node context, QName qname)
Parameter | Description |
---|---|
context | The root node to perform the search on. |
qname | The QName to search for. |
public static Element[] getElements(Node context, QName qname)
//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; } }