| /** |
| * 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. |
| */ |
| |
| package org.apache.cxf.helpers; |
| |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedHashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.WeakHashMap; |
| |
| import javax.xml.XMLConstants; |
| import javax.xml.namespace.QName; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Comment; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.DocumentFragment; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| import org.apache.cxf.common.logging.LogUtils; |
| import org.apache.cxf.common.util.ReflectionUtil; |
| import org.apache.cxf.common.util.StringUtils; |
| |
| /** |
| * Few simple utils to read DOM. This is originally from the Jakarta Commons Modeler. |
| */ |
| public final class DOMUtils { |
| private static boolean isJre9SAAJ; |
| private static final Map<ClassLoader, DocumentBuilder> DOCUMENT_BUILDERS |
| = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder>()); |
| private static final String XMLNAMESPACE = "xmlns"; |
| private static volatile Document emptyDocument; |
| |
| private static final ClassValue<Method> GET_DOM_ELEMENTS_METHODS = new ClassValue<Method>() { |
| @Override |
| protected Method computeValue(Class<?> type) { |
| try { |
| return ReflectionUtil.getMethod(type, "getDomElement"); |
| } catch (NoSuchMethodException e) { |
| //best effort to try, do nothing if NoSuchMethodException |
| return null; |
| } |
| } |
| }; |
| private static final ClassValue<Field> GET_DOCUMENT_FRAGMENT_FIELDS = new ClassValue<Field>() { |
| @Override |
| protected Field computeValue(Class<?> type) { |
| return ReflectionUtil.getDeclaredField(type, "documentFragment"); |
| } |
| |
| }; |
| |
| static { |
| try { |
| Method[] methods = DOMUtils.class.getClassLoader(). |
| loadClass("com.sun.xml.messaging.saaj.soap.SOAPDocumentImpl").getMethods(); |
| for (Method method : methods) { |
| if ("register".equals(method.getName())) { |
| //this is the 1.4+ SAAJ impl |
| setJava9SAAJ(true); |
| break; |
| } |
| } |
| } catch (ClassNotFoundException cnfe) { |
| LogUtils.getL7dLogger(DOMUtils.class).finest( |
| "can't load class com.sun.xml.messaging.saaj.soap.SOAPDocumentImpl"); |
| |
| try { |
| Method[] methods = DOMUtils.class.getClassLoader(). |
| loadClass("com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl").getMethods(); |
| for (Method method : methods) { |
| if ("register".equals(method.getName())) { |
| //this is the SAAJ impl in JDK9 |
| setJava9SAAJ(true); |
| break; |
| } |
| } |
| } catch (ClassNotFoundException cnfe1) { |
| LogUtils.getL7dLogger(DOMUtils.class).finest( |
| "can't load class com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl"); |
| } |
| } catch (Throwable throwable) { |
| LogUtils.getL7dLogger(DOMUtils.class).finest( |
| "Other JDK vendor"); |
| } |
| } |
| |
| private DOMUtils() { |
| } |
| |
| private static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException { |
| ClassLoader loader = getContextClassLoader(); |
| if (loader == null) { |
| loader = getClassLoader(DOMUtils.class); |
| } |
| if (loader == null) { |
| return createDocumentBuilder(); |
| } |
| DocumentBuilder factory = DOCUMENT_BUILDERS.get(loader); |
| if (factory == null) { |
| factory = createDocumentBuilder(); |
| DOCUMENT_BUILDERS.put(loader, factory); |
| } |
| return factory; |
| } |
| |
| private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { |
| DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); |
| f.setNamespaceAware(true); |
| f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true); |
| f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); |
| return f.newDocumentBuilder(); |
| } |
| |
| private static ClassLoader getContextClassLoader() { |
| final SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { |
| public ClassLoader run() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| }); |
| } |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| |
| private static ClassLoader getClassLoader(final Class<?> clazz) { |
| final SecurityManager sm = System.getSecurityManager(); |
| if (sm != null) { |
| return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { |
| public ClassLoader run() { |
| return clazz.getClassLoader(); |
| } |
| }); |
| } |
| return clazz.getClassLoader(); |
| } |
| |
| /** |
| * Creates a new Document object |
| * @throws ParserConfigurationException |
| */ |
| public static Document newDocument() { |
| return createDocument(); |
| } |
| public static Document createDocument() { |
| try { |
| return getDocumentBuilder().newDocument(); |
| } catch (ParserConfigurationException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private static synchronized Document createEmptyDocument() { |
| if (emptyDocument == null) { |
| emptyDocument = createDocument(); |
| |
| // uncomment this to see if anything is actually setting anything into the empty doc |
| /* |
| final Document doc = createDocument(); |
| emptyDocument = (Document)org.apache.cxf.common.util.ProxyHelper.getProxy( |
| DOMUtils.class.getClassLoader(), |
| new Class<?>[] {Document.class}, |
| new java.lang.reflect.InvocationHandler() { |
| @Override |
| public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { |
| if (method.getName().contains("create")) { |
| return method.invoke(doc, args); |
| } |
| throw new IllegalStateException("Cannot modify factory document"); |
| } |
| }); |
| */ |
| } |
| return emptyDocument; |
| } |
| /** |
| * Returns a static Document that should always be "empty". It's useful as a factory for |
| * for creating Elements and other nodes that will be traversed later and don't need to |
| * be attached into a document |
| * @return an empty document |
| */ |
| public static Document getEmptyDocument() { |
| Document doc = emptyDocument; |
| if (doc == null) { |
| doc = createEmptyDocument(); |
| } |
| return doc; |
| } |
| |
| |
| /** |
| * This function is much like getAttribute, but returns null, not "", for a nonexistent attribute. |
| * |
| * @param e |
| * @param attributeName |
| */ |
| public static String getAttributeValueEmptyNull(Element e, String attributeName) { |
| Attr node = e.getAttributeNode(attributeName); |
| if (node == null) { |
| return null; |
| } |
| return node.getValue(); |
| } |
| |
| /** |
| * Get the text content of a node and all it's children or null if there is no text |
| */ |
| public static String getAllContent(Node n) { |
| StringBuilder b = new StringBuilder(); |
| getAllContent(n, b); |
| return b.toString(); |
| } |
| private static void getAllContent(Node n, StringBuilder b) { |
| Node nd = n.getFirstChild(); |
| while (nd != null) { |
| if (nd instanceof Text && !(nd instanceof Comment)) { |
| b.append(((Text)nd).getData()); |
| } else { |
| getAllContent(nd, b); |
| } |
| nd = nd.getNextSibling(); |
| } |
| } |
| /** |
| * Get the trimmed text content of a node or null if there is no text |
| */ |
| public static String getContent(Node n) { |
| String s = getRawContent(n); |
| if (s != null) { |
| s = s.trim(); |
| } |
| return s; |
| } |
| |
| /** |
| * Get the raw text content of a node or null if there is no text |
| */ |
| public static String getRawContent(Node n) { |
| if (n == null) { |
| return null; |
| } |
| StringBuilder b = null; |
| String s = null; |
| Node n1 = n.getFirstChild(); |
| while (n1 != null) { |
| if (n1.getNodeType() == Node.TEXT_NODE || n1.getNodeType() == Node.CDATA_SECTION_NODE) { |
| if (b != null) { |
| b.append(((Text)n1).getNodeValue()); |
| } else if (s == null) { |
| s = ((Text)n1).getNodeValue(); |
| } else { |
| b = new StringBuilder(s).append(((Text)n1).getNodeValue()); |
| s = null; |
| } |
| } |
| n1 = n1.getNextSibling(); |
| } |
| if (b != null) { |
| return b.toString(); |
| } |
| return s; |
| } |
| |
| /** |
| * Get the first element child. |
| * |
| * @param parent lookup direct childs |
| * @param name name of the element. If null return the first element. |
| */ |
| public static Node getChild(Node parent, String name) { |
| if (parent == null) { |
| return null; |
| } |
| |
| Node first = parent.getFirstChild(); |
| if (first == null) { |
| return null; |
| } |
| |
| for (Node node = first; node != null; node = node.getNextSibling()) { |
| |
| if (node.getNodeType() != Node.ELEMENT_NODE) { |
| continue; |
| } |
| if (name != null && name.equals(node.getNodeName())) { |
| return node; |
| } |
| if (name == null) { |
| return node; |
| } |
| } |
| return null; |
| } |
| |
| |
| public static boolean hasAttribute(Element element, String value) { |
| NamedNodeMap attributes = element.getAttributes(); |
| for (int i = 0; i < attributes.getLength(); i++) { |
| Node node = attributes.item(i); |
| if (value.equals(node.getNodeValue())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| public static String getAttribute(Node element, String attName) { |
| NamedNodeMap attrs = element.getAttributes(); |
| if (attrs == null) { |
| return null; |
| } |
| Node attN = attrs.getNamedItem(attName); |
| if (attN == null) { |
| return null; |
| } |
| return attN.getNodeValue(); |
| } |
| |
| public static String getAttribute(Element element, QName attName) { |
| Attr attr; |
| if (StringUtils.isEmpty(attName.getNamespaceURI())) { |
| attr = element.getAttributeNode(attName.getLocalPart()); |
| } else { |
| attr = element.getAttributeNodeNS(attName.getNamespaceURI(), attName.getLocalPart()); |
| } |
| return attr == null ? null : attr.getValue(); |
| } |
| |
| public static void setAttribute(Node node, String attName, String val) { |
| NamedNodeMap attributes = node.getAttributes(); |
| Node attNode = node.getOwnerDocument().createAttributeNS(null, attName); |
| attNode.setNodeValue(val); |
| attributes.setNamedItem(attNode); |
| } |
| |
| public static void removeAttribute(Node node, String attName) { |
| NamedNodeMap attributes = node.getAttributes(); |
| attributes.removeNamedItem(attName); |
| } |
| |
| /** |
| * Set or replace the text value |
| */ |
| public static void setText(Node node, String val) { |
| Node chld = DOMUtils.getChild(node, Node.TEXT_NODE); |
| if (chld == null) { |
| Node textN = node.getOwnerDocument().createTextNode(val); |
| node.appendChild(textN); |
| return; |
| } |
| // change the value |
| chld.setNodeValue(val); |
| } |
| |
| /** |
| * Find the first direct child with a given attribute. |
| * |
| * @param parent |
| * @param elemName name of the element, or null for any |
| * @param attName attribute we're looking for |
| * @param attVal attribute value or null if we just want any |
| */ |
| public static Element findChildWithAtt(Node parent, String elemName, String attName, String attVal) { |
| |
| Element child = (Element)getChild(parent, Node.ELEMENT_NODE); |
| if (attVal == null) { |
| while (child != null && (elemName == null || elemName.equals(child.getNodeName())) |
| && DOMUtils.getAttribute(child, attName) != null) { |
| child = (Element)getNext(child, elemName, Node.ELEMENT_NODE); |
| } |
| } else { |
| while (child != null && (elemName == null || elemName.equals(child.getNodeName())) |
| && !attVal.equals(DOMUtils.getAttribute(child, attName))) { |
| child = (Element)getNext(child, elemName, Node.ELEMENT_NODE); |
| } |
| } |
| return child; |
| } |
| |
| /** |
| * Get the first child's content ( ie it's included TEXT node ). |
| */ |
| public static String getChildContent(Node parent, String name) { |
| Node first = parent.getFirstChild(); |
| if (first == null) { |
| return null; |
| } |
| for (Node node = first; node != null; node = node.getNextSibling()) { |
| |
| if (name.equals(node.getNodeName())) { |
| return getRawContent(node); |
| } |
| } |
| return null; |
| } |
| |
| public static QName getElementQName(Element el) { |
| return new QName(el.getNamespaceURI(), el.getLocalName()); |
| } |
| |
| /** |
| * Creates a QName object based on the qualified name |
| * and using the Node as a base to lookup the namespace |
| * for the prefix |
| * @param qualifiedName |
| * @param node |
| */ |
| public static QName createQName(String qualifiedName, Node node) { |
| if (qualifiedName == null) { |
| return null; |
| } |
| |
| int index = qualifiedName.indexOf(':'); |
| |
| if (index == -1) { |
| return new QName(qualifiedName); |
| } |
| |
| String prefix = qualifiedName.substring(0, index); |
| String localName = qualifiedName.substring(index + 1); |
| String ns = node.lookupNamespaceURI(prefix); |
| |
| if (ns == null) { |
| throw new RuntimeException("Invalid QName in mapping: " + qualifiedName); |
| } |
| |
| return new QName(ns, localName, prefix); |
| } |
| |
| public static QName convertStringToQName(String expandedQName) { |
| return convertStringToQName(expandedQName, ""); |
| } |
| |
| public static QName convertStringToQName(String expandedQName, String prefix) { |
| int ind1 = expandedQName.indexOf('{'); |
| if (ind1 != 0) { |
| return new QName(expandedQName); |
| } |
| |
| int ind2 = expandedQName.indexOf('}'); |
| if (ind2 <= ind1 + 1 || ind2 >= expandedQName.length() - 1) { |
| return null; |
| } |
| String ns = expandedQName.substring(ind1 + 1, ind2); |
| String localName = expandedQName.substring(ind2 + 1); |
| return new QName(ns, localName, prefix); |
| } |
| public static Set<QName> convertStringsToQNames(List<String> expandedQNames) { |
| Set<QName> dropElements = Collections.emptySet(); |
| if (expandedQNames != null) { |
| dropElements = new LinkedHashSet<>(expandedQNames.size()); |
| for (String val : expandedQNames) { |
| dropElements.add(convertStringToQName(val)); |
| } |
| } |
| return dropElements; |
| } |
| |
| |
| /** |
| * Get the first direct child with a given type |
| */ |
| public static Element getFirstElement(Node parent) { |
| Node n = parent.getFirstChild(); |
| while (n != null && Node.ELEMENT_NODE != n.getNodeType()) { |
| n = n.getNextSibling(); |
| } |
| if (n == null) { |
| return null; |
| } |
| return (Element)n; |
| } |
| |
| public static Element getNextElement(Element el) { |
| Node nd = el.getNextSibling(); |
| while (nd != null) { |
| if (nd.getNodeType() == Node.ELEMENT_NODE) { |
| return (Element)nd; |
| } |
| nd = nd.getNextSibling(); |
| } |
| return null; |
| } |
| |
| /** |
| * Return the first element child with the specified qualified name. |
| * |
| * @param parent |
| * @param q |
| */ |
| public static Element getFirstChildWithName(Element parent, QName q) { |
| String ns = q.getNamespaceURI(); |
| String lp = q.getLocalPart(); |
| return getFirstChildWithName(parent, ns, lp); |
| } |
| |
| /** |
| * Return the first element child with the specified qualified name. |
| * |
| * @param parent |
| * @param ns |
| * @param lp |
| */ |
| public static Element getFirstChildWithName(Element parent, String ns, String lp) { |
| for (Node n = parent.getFirstChild(); n != null; n = n.getNextSibling()) { |
| if (n instanceof Element) { |
| Element e = (Element)n; |
| String ens = (e.getNamespaceURI() == null) ? "" : e.getNamespaceURI(); |
| if (ns.equals(ens) && lp.equals(e.getLocalName())) { |
| return e; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return child elements with specified name. |
| * |
| * @param parent |
| * @param ns |
| * @param localName |
| */ |
| public static List<Element> getChildrenWithName(Element parent, String ns, String localName) { |
| List<Element> r = new ArrayList<>(); |
| for (Node n = parent.getFirstChild(); n != null; n = n.getNextSibling()) { |
| if (n instanceof Element) { |
| Element e = (Element)n; |
| String eNs = (e.getNamespaceURI() == null) ? "" : e.getNamespaceURI(); |
| if (ns.equals(eNs) && localName.equals(e.getLocalName())) { |
| r.add(e); |
| } |
| } |
| } |
| return r; |
| } |
| |
| /** |
| * Returns all child elements with specified namespace. |
| * |
| * @param parent the element to search under |
| * @param ns the namespace to find elements in |
| * @return all child elements with specified namespace |
| */ |
| public static List<Element> getChildrenWithNamespace(Element parent, String ns) { |
| List<Element> r = new ArrayList<>(); |
| for (Node n = parent.getFirstChild(); n != null; n = n.getNextSibling()) { |
| if (n instanceof Element) { |
| Element e = (Element)n; |
| String eNs = (e.getNamespaceURI() == null) ? "" : e.getNamespaceURI(); |
| if (ns.equals(eNs)) { |
| r.add(e); |
| } |
| } |
| } |
| return r; |
| } |
| |
| /** |
| * Get the first child of the specified type. |
| * |
| * @param parent |
| * @param type |
| */ |
| public static Node getChild(Node parent, int type) { |
| Node n = parent.getFirstChild(); |
| while (n != null && type != n.getNodeType()) { |
| n = n.getNextSibling(); |
| } |
| if (n == null) { |
| return null; |
| } |
| return n; |
| } |
| |
| /** |
| * Get the next sibling with the same name and type |
| */ |
| public static Node getNext(Node current) { |
| String name = current.getNodeName(); |
| int type = current.getNodeType(); |
| return getNext(current, name, type); |
| } |
| |
| /** |
| * Return the next sibling with a given name and type |
| */ |
| public static Node getNext(Node current, String name, int type) { |
| Node first = current.getNextSibling(); |
| if (first == null) { |
| return null; |
| } |
| |
| for (Node node = first; node != null; node = node.getNextSibling()) { |
| |
| if (type >= 0 && node.getNodeType() != type) { |
| continue; |
| } |
| |
| if (name == null) { |
| return node; |
| } |
| if (name.equals(node.getNodeName())) { |
| return node; |
| } |
| } |
| return null; |
| } |
| |
| public static class NullResolver implements EntityResolver { |
| public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { |
| return new InputSource(new StringReader("")); |
| } |
| } |
| |
| public static String getPrefixRecursive(Element el, String ns) { |
| String prefix = getPrefix(el, ns); |
| if (prefix == null && el.getParentNode() instanceof Element) { |
| prefix = getPrefixRecursive((Element)el.getParentNode(), ns); |
| } |
| return prefix; |
| } |
| |
| public static String getPrefix(Element el, String ns) { |
| NamedNodeMap atts = el.getAttributes(); |
| for (int i = 0; i < atts.getLength(); i++) { |
| Node node = atts.item(i); |
| String name = node.getNodeName(); |
| if (ns.equals(node.getNodeValue()) |
| && (name != null && (XMLNAMESPACE.equals(name) || name.startsWith(XMLNAMESPACE + ":")))) { |
| return node.getLocalName(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get all prefixes defined, up to the root, for a namespace URI. |
| * |
| * @param element |
| * @param namespaceUri |
| * @param prefixes |
| */ |
| public static void getPrefixesRecursive(Element element, String namespaceUri, List<String> prefixes) { |
| getPrefixes(element, namespaceUri, prefixes); |
| Node parent = element.getParentNode(); |
| if (parent instanceof Element) { |
| getPrefixesRecursive((Element)parent, namespaceUri, prefixes); |
| } |
| } |
| |
| /** |
| * Get all prefixes defined on this element for the specified namespace. |
| * |
| * @param element |
| * @param namespaceUri |
| * @param prefixes |
| */ |
| public static void getPrefixes(Element element, String namespaceUri, List<String> prefixes) { |
| NamedNodeMap atts = element.getAttributes(); |
| for (int i = 0; i < atts.getLength(); i++) { |
| Node node = atts.item(i); |
| String name = node.getNodeName(); |
| if (namespaceUri.equals(node.getNodeValue()) |
| && (name != null && (XMLNAMESPACE.equals(name) || name.startsWith(XMLNAMESPACE + ":")))) { |
| prefixes.add(node.getPrefix()); |
| } |
| } |
| } |
| |
| public static String createNamespace(Element el, String ns) { |
| String p = "ns1"; |
| int i = 1; |
| while (getPrefix(el, ns) != null) { |
| p = "ns" + i; |
| i++; |
| } |
| addNamespacePrefix(el, ns, p); |
| return p; |
| } |
| |
| /** |
| * Starting from a node, find the namespace declaration for a prefix. for a matching namespace |
| * declaration. |
| * |
| * @param node search up from here to search for namespace definitions |
| * @param searchPrefix the prefix we are searching for |
| * @return the namespace if found. |
| */ |
| public static String getNamespace(Node node, String searchPrefix) { |
| |
| Element el; |
| while (!(node instanceof Element)) { |
| node = node.getParentNode(); |
| } |
| el = (Element)node; |
| |
| NamedNodeMap atts = el.getAttributes(); |
| for (int i = 0; i < atts.getLength(); i++) { |
| Node currentAttribute = atts.item(i); |
| String currentLocalName = currentAttribute.getLocalName(); |
| String currentPrefix = currentAttribute.getPrefix(); |
| if (searchPrefix.equals(currentLocalName) && XMLNAMESPACE.equals(currentPrefix)) { |
| return currentAttribute.getNodeValue(); |
| } else if (StringUtils.isEmpty(searchPrefix) && XMLNAMESPACE.equals(currentLocalName) |
| && StringUtils.isEmpty(currentPrefix)) { |
| return currentAttribute.getNodeValue(); |
| } |
| } |
| |
| Node parent = el.getParentNode(); |
| if (parent instanceof Element) { |
| return getNamespace(parent, searchPrefix); |
| } |
| |
| return null; |
| } |
| |
| public static List<Element> findAllElementsByTagNameNS(Element elem, String nameSpaceURI, |
| String localName) { |
| List<Element> ret = new LinkedList<>(); |
| findAllElementsByTagNameNS(elem, nameSpaceURI, localName, ret); |
| return ret; |
| } |
| |
| /** |
| * Try to get the DOM Node from the SAAJ Node with JAVA9 afterwards |
| * @param node The original node we need check |
| * @return The DOM node |
| */ |
| public static Node getDomElement(Node node) { |
| if (node != null && isJava9SAAJ()) { |
| //java9plus hack |
| Method method = GET_DOM_ELEMENTS_METHODS.get(node.getClass()); |
| if (method != null) { |
| try { |
| return (Node)ReflectionUtil.setAccessible(method).invoke(node); |
| } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| return node; |
| } |
| |
| /** |
| * Try to get the DOM DocumentFragment from the SAAJ DocumentFragment with JAVA9 afterwards |
| * @param fragment The original documentFragment we need to check |
| * @return The DOM DocumentFragment |
| */ |
| public static DocumentFragment getDomDocumentFragment(DocumentFragment fragment) { |
| if (fragment != null && isJava9SAAJ()) { |
| //java9 plus hack |
| Field f = GET_DOCUMENT_FRAGMENT_FIELDS.get(fragment.getClass()); |
| if (f != null) { |
| return ReflectionUtil.accessDeclaredField(f, fragment, DocumentFragment.class); |
| } |
| } |
| return fragment; |
| } |
| |
| private static void findAllElementsByTagNameNS(Element el, String nameSpaceURI, String localName, |
| List<Element> elementList) { |
| |
| if (el.getNamespaceURI() != null && localName.equals(el.getLocalName()) |
| && nameSpaceURI.contains(el.getNamespaceURI())) { |
| elementList.add(el); |
| } |
| Element elem = getFirstElement(el); |
| while (elem != null) { |
| findAllElementsByTagNameNS(elem, nameSpaceURI, localName, elementList); |
| elem = getNextElement(elem); |
| } |
| } |
| |
| public static List<Element> findAllElementsByTagName(Element elem, String tagName) { |
| List<Element> ret = new LinkedList<>(); |
| findAllElementsByTagName(elem, tagName, ret); |
| return ret; |
| } |
| |
| private static void findAllElementsByTagName(Element el, String tagName, List<Element> elementList) { |
| |
| if (tagName.equals(el.getTagName())) { |
| elementList.add(el); |
| } |
| Element elem = getFirstElement(el); |
| while (elem != null) { |
| findAllElementsByTagName(elem, tagName, elementList); |
| elem = getNextElement(elem); |
| } |
| } |
| public static boolean hasElementWithName(Element el, String nameSpaceURI, String localName) { |
| if (el.getNamespaceURI() != null && localName.equals(el.getLocalName()) |
| && nameSpaceURI.contains(el.getNamespaceURI())) { |
| return true; |
| } |
| Element elem = getFirstElement(el); |
| while (elem != null) { |
| if (hasElementWithName(elem, nameSpaceURI, localName)) { |
| return true; |
| } |
| elem = getNextElement(elem); |
| } |
| return false; |
| } |
| public static boolean hasElementInNS(Element el, String namespace) { |
| |
| if (namespace.equals(el.getNamespaceURI())) { |
| return true; |
| } |
| Element elem = getFirstElement(el); |
| while (elem != null) { |
| if (hasElementInNS(elem, namespace)) { |
| return true; |
| } |
| elem = getNextElement(elem); |
| } |
| return false; |
| } |
| /** |
| * Set a namespace/prefix on an element if it is not set already. First off, it searches for the element |
| * for the prefix associated with the specified namespace. If the prefix isn't null, then this is |
| * returned. Otherwise, it creates a new attribute using the namespace/prefix passed as parameters. |
| * |
| * @param element |
| * @param namespace |
| * @param prefix |
| * @return the prefix associated with the set namespace |
| */ |
| public static String setNamespace(Element element, String namespace, String prefix) { |
| String pre = getPrefixRecursive(element, namespace); |
| if (pre != null) { |
| return pre; |
| } |
| element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:" + prefix, namespace); |
| return prefix; |
| } |
| |
| /** |
| * Add a namespace prefix definition to an element. |
| * |
| * @param element |
| * @param namespaceUri |
| * @param prefix |
| */ |
| public static void addNamespacePrefix(Element element, String namespaceUri, String prefix) { |
| element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, "xmlns:" + prefix, namespaceUri); |
| } |
| |
| public static boolean isJava9SAAJ() { |
| return isJre9SAAJ; |
| } |
| |
| private static void setJava9SAAJ(boolean isJava9SAAJ) { |
| DOMUtils.isJre9SAAJ = isJava9SAAJ; |
| } |
| } |