/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.support.xml; import com.eviware.soapui.SoapUI; import com.eviware.soapui.impl.wsdl.WsdlInterface; import com.eviware.soapui.impl.wsdl.support.Constants; import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.types.StringToStringMap; import net.sf.saxon.expr.Token; import net.sf.saxon.expr.Tokenizer; import org.apache.log4j.Logger; import org.apache.xerces.util.SecurityManager; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.apache.xmlbeans.SchemaType; import org.apache.xmlbeans.XmlAnySimpleType; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlCursor.TokenType; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; 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.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.net.URL; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; /** * General XML-related utilities */ @SuppressWarnings("deprecation") public final class XmlUtils { private static DocumentBuilder documentBuilder; private final static Logger log = Logger.getLogger(XmlUtils.class); static synchronized public Document parse(InputStream in) { try { return ensureDocumentBuilder().parse(in); } catch (Exception e) { log.error("Error parsing InputStream; " + e.getMessage(), e); } return null; } static synchronized public Document parse(String fileName) throws IOException { try { return ensureDocumentBuilder().parse(fileName); } catch (SAXException e) { log.error("Error parsing fileName [" + fileName + "]; " + e.getMessage(), e); } return null; } public static String entitize(String xml) { return xml.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">") .replaceAll("\"", """).replaceAll("'", "'"); } public static String entitizeContent(String xml) { return xml.replaceAll("&", "&").replaceAll("\"", """).replaceAll("'", "'"); } static synchronized public Document parse(InputSource inputSource) throws IOException { try { return ensureDocumentBuilder().parse(inputSource); } catch (SAXException e) { throw new IOException(e.toString()); } } private static DocumentBuilder ensureDocumentBuilder() { if (documentBuilder == null) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); documentBuilder = dbf.newDocumentBuilder(); } catch (ParserConfigurationException e) { log.error("Error creating DocumentBuilder; " + e.getMessage()); } } return documentBuilder; } public static String serializePretty(Document document) { try { Writer out = new StringWriter(); serializePretty(document, out); return out.toString(); } catch (IOException e) { log.error("Failed to serialize: " + e); } return null; } public static void serializePretty(Document dom, Writer writer) throws IOException { try { XmlObject xmlObject = XmlObject.Factory.parse(dom.getDocumentElement()); serializePretty(xmlObject, writer); } catch (Exception e) { throw new IOException(e.toString()); } } public static void serializePretty(XmlObject xmlObject, Writer writer) throws IOException { XmlOptions options = new XmlOptions(); options.setSavePrettyPrint(); options.setSavePrettyPrintIndent(3); options.setSaveNoXmlDecl(); options.setSaveAggressiveNamespaces(); // StringToStringMap map = new StringToStringMap(); // map.put( SoapVersion.Soap11.getEnvelopeNamespace(), "SOAPENV" ); // map.put( SoapVersion.Soap12.getEnvelopeNamespace(), "SOAPENV" ); // // options.setSaveSuggestedPrefixes( map ); xmlObject.save(writer, options); } public static XmlObject createXmlObject(InputStream input, XmlOptions xmlOptions) throws XmlException { try { return XmlObject.Factory.parse(input, xmlOptions); } catch (Exception e) { throw new XmlException(e.toString()); } } public static XmlObject createXmlObject(String input, XmlOptions xmlOptions) throws XmlException { return XmlObject.Factory.parse(input, xmlOptions); } public static XmlObject createXmlObject(URL input, XmlOptions xmlOptions) throws XmlException { try { return XmlObject.Factory.parse(input, xmlOptions); } catch (Exception e) { throw new XmlException(e.toString()); } } public static XmlObject createXmlObject(Node input, XmlOptions xmlOptions) throws XmlException { return XmlObject.Factory.parse(input, xmlOptions); } public static XmlObject createXmlObject(File input, XmlOptions xmlOptions) throws XmlException { try { return XmlObject.Factory.parse(input, xmlOptions); } catch (Exception e) { throw new XmlException(e.toString()); } } public static XmlObject createXmlObject(InputStream input) throws XmlException { try { return XmlObject.Factory.parse(input); } catch (Exception e) { throw new XmlException(e.toString()); } } public static XmlObject createXmlObject(String input) throws XmlException { return XmlObject.Factory.parse(input); } public static XmlObject createXmlObject(URL input) throws XmlException { try { return XmlObject.Factory.parse(input); } catch (Exception e) { throw new XmlException(e.toString()); } } public static XmlObject createXmlObject(Node input) throws XmlException { return XmlObject.Factory.parse(input); } public static XmlObject createXmlObject(File input) throws XmlException { try { return XmlObject.Factory.parse(input); } catch (Exception e) { throw new XmlException(e.toString()); } } /** * XmlOptions configuration used in preventing XML Bomb * * @return XmlOptions */ public static XmlOptions createDefaultXmlOptions() { XmlOptions xmlOptions; try { SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); SecurityManager securityManager = new SecurityManager(); // Default seems to be 64000! securityManager.setEntityExpansionLimit(16); saxParser.setProperty("http://apache.org/xml/properties/security-manager", securityManager); XMLReader xmlReader = saxParser.getXMLReader(); xmlOptions = new XmlOptions().setLoadUseXMLReader(xmlReader); } catch (Exception e) { xmlOptions = new XmlOptions(); log.error("Error creating XmlOptions; " + e.getMessage(), e); } return xmlOptions; } public static void serialize(Document dom, Writer writer) throws IOException { serialize(dom.getDocumentElement(), writer); } public static void serialize(Element elm, Writer writer) throws IOException { try { XmlObject xmlObject = XmlObject.Factory.parse(elm); xmlObject.save(writer); } catch (XmlException e) { throw new IOException(e.toString()); } } static public String serialize(Node node, boolean prettyPrint) { try { XmlObject xmlObject = XmlObject.Factory.parse(node); return prettyPrint ? xmlObject.xmlText(new XmlOptions().setSavePrettyPrint()) : xmlObject.xmlText(); } catch (XmlException e) { return e.toString(); } } static public void setElementText(Element elm, String text) { Node node = elm.getFirstChild(); if (node == null) { if (text != null) { elm.appendChild(elm.getOwnerDocument().createTextNode(text)); } } else if (node.getNodeType() == Node.TEXT_NODE) { if (text == null) { node.getParentNode().removeChild(node); } else { node.setNodeValue(text); } } else if (text != null) { Text textNode = node.getOwnerDocument().createTextNode(text); elm.insertBefore(textNode, elm.getFirstChild()); } } public static String getChildElementText(Element elm, String name) { Element child = getFirstChildElement(elm, name); return child == null ? null : getElementText(child); } public static Element getFirstChildElement(Element elm) { return getFirstChildElement(elm, null); } public static Element getFirstChildElement(Element elm, String name) { if (elm == null) { return null; } NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node node = nl.item(c); if (node.getNodeType() == Node.ELEMENT_NODE && (name == null || node.getNodeName().equals(name))) { return (Element) node; } } return null; } public static Element getFirstChildElementIgnoreCase(Element elm, String name) { if (elm == null) { return null; } NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node node = nl.item(c); if (node.getNodeType() == Node.ELEMENT_NODE && (name == null || node.getNodeName().equalsIgnoreCase(name))) { return (Element) node; } } return null; } public static Element getFirstChildElementNS(Element elm, String tns, String localName) { if (tns == null && localName == null) { return getFirstChildElement(elm); } if (tns == null || tns.length() == 0) { return getFirstChildElement(elm, localName); } NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node node = nl.item(c); if (node.getNodeType() != Node.ELEMENT_NODE) { continue; } if (localName == null && tns.equals(node.getNamespaceURI())) { return (Element) node; } if (localName != null && tns.equals(node.getNamespaceURI()) && localName.equals(node.getLocalName())) { return (Element) node; } } return null; } static public String getElementText(Element elm) { Node node = elm.getFirstChild(); if (node != null && node.getNodeType() == Node.TEXT_NODE) { return node.getNodeValue(); } return null; } static public String getFragmentText(DocumentFragment elm) { Node node = elm.getFirstChild(); if (node != null && node.getNodeType() == Node.TEXT_NODE) { return node.getNodeValue(); } return null; } public static String getChildElementText(Element elm, String name, String defaultValue) { String result = getChildElementText(elm, name); return result == null ? defaultValue : result; } static public String getNodeValue(Node node) { if (node == null) { return null; } if (node.getNodeType() == Node.ELEMENT_NODE) { return getElementText((Element) node); } else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) { return getFragmentText((DocumentFragment) node); } else { return node.getNodeValue(); } } public static Node createNodeFromPath(Element modelElement, String path) { Document document = modelElement.getOwnerDocument(); StringTokenizer st = new StringTokenizer(path, "/"); while (st.hasMoreTokens()) { String t = st.nextToken(); if (st.hasMoreTokens()) { if (t.equals("..")) { modelElement = (Element) modelElement.getParentNode(); } else { Element elm = getFirstChildElement(modelElement, t); if (elm == null) { modelElement = (Element) modelElement.insertBefore(document.createElement(t), getFirstChildElement(modelElement, t)); } else { modelElement = elm; } } } else { modelElement = (Element) modelElement.insertBefore(document.createElement(t), getFirstChildElement(modelElement, t)); } } return modelElement; } public static Element addChildElement(Element element, String name, String text) { Document document = element.getOwnerDocument(); Element result = (Element) element.appendChild(document.createElement(name)); if (text != null) { result.appendChild(document.createTextNode(text)); } return result; } public static void setChildElementText(Element element, String name, String text) { Element elm = getFirstChildElement(element, name); if (elm == null) { elm = element.getOwnerDocument().createElement(name); element.appendChild(elm); } setElementText(elm, text); } public static Document parseXml(String xmlString) throws IOException { return parse(new InputSource(new StringReader(xmlString))); } public static String transferValues(String source, String dest) { if (StringUtils.isNullOrEmpty(source) || StringUtils.isNullOrEmpty(dest)) { return dest; } XmlCursor cursor = null; try { XmlObject sourceXml = XmlObject.Factory.parse(source); XmlObject destXml = XmlObject.Factory.parse(dest); cursor = sourceXml.newCursor(); cursor.toNextToken(); while (!cursor.isEnddoc()) { while (!cursor.isContainer() && !cursor.isEnddoc()) { cursor.toNextToken(); } if (cursor.isContainer()) { Element elm = (Element) cursor.getDomNode(); String path = createXPath(elm); XmlObject[] paths = destXml.selectPath(path); if (paths != null && paths.length > 0) { Element elm2 = (Element) paths[0].getDomNode(); // transfer attributes transferAttributes(elm, elm2); // transfer text setElementText(elm2, getElementText(elm)); while (elm.getNextSibling() != null && elm2.getNextSibling() != null && elm.getNextSibling().getNodeName().equals(elm.getNodeName()) && !elm2.getNextSibling().getNodeName().equals(elm2.getNodeName())) { elm2 = (Element) elm2.getParentNode().insertBefore( elm2.getOwnerDocument().createElementNS(elm2.getNamespaceURI(), elm2.getLocalName()), elm2.getNextSibling()); elm = (Element) elm.getNextSibling(); // transfer attributes transferAttributes(elm, elm2); // transfer text setElementText(elm2, getElementText(elm)); } } cursor.toNextToken(); } } return destXml.xmlText(); } catch (Exception e) { SoapUI.logError(e); } finally { if (cursor != null) { cursor.dispose(); } } return dest; } private static void transferAttributes(Element elm, Element elm2) { NamedNodeMap attributes = elm.getAttributes(); for (int c = 0; c < attributes.getLength(); c++) { Attr attr = (Attr) attributes.item(c); elm2.setAttributeNodeNS((Attr) elm2.getOwnerDocument().importNode(attr, true)); } } /** * Returns absolute xpath for specified element, ignores namespaces * * @param element the element to create for * @return the elements path in its containing document */ public static String getElementPath(Element element) { Node elm = element; String result = elm.getNodeName() + "[" + getElementIndex(elm) + "]"; while (elm.getParentNode() != null && elm.getParentNode().getNodeType() != Node.DOCUMENT_NODE) { elm = elm.getParentNode(); result = elm.getNodeName() + "[" + getElementIndex(elm) + "]/" + result; } return "/" + result; } /** * Gets the index of the specified element amongst elements with the same * name * * @param element the element to get for * @return the index of the element, will be >= 1 */ public static int getElementIndex(Node element) { int result = 1; Node elm = element.getPreviousSibling(); while (elm != null) { if (elm.getNodeType() == Node.ELEMENT_NODE && elm.getNodeName().equals(element.getNodeName())) { result++; } elm = elm.getPreviousSibling(); } return result; } public static String declareXPathNamespaces(String xmlString) throws XmlException { return declareXPathNamespaces(XmlObject.Factory.parse(xmlString)); } public static synchronized String prettyPrintXml(String xml) { try { if (!XmlUtils.seemsToBeXml(xml)) { return xml; } StringWriter writer = new StringWriter(); XmlUtils.serializePretty(XmlObject.Factory.parse(xml), writer); return writer.toString(); } catch (Exception e) { log.warn("Failed to prettyPrint xml [" + xml + "]: " + e); return xml; } } public static synchronized String prettyPrintXml(XmlObject xml) { if (xml == null) { return null; } try { StringWriter writer = new StringWriter(); XmlUtils.serializePretty(xml, writer); return writer.toString(); } catch (Exception e) { log.warn("Failed to prettyPrint xml [" + xml + "]: " + e); return xml.xmlText(); } } public static String declareXPathNamespaces(WsdlInterface iface) { StringBuilder buf = new StringBuilder(); buf.append("declare namespace soap='"); buf.append(iface.getSoapVersion().getEnvelopeNamespace()); buf.append("';\n"); try { Collection<String> namespaces = iface.getWsdlContext().getInterfaceDefinition().getDefinedNamespaces(); int c = 1; for (String namespace : namespaces) { buf.append("declare namespace ns"); buf.append(c++); buf.append("='"); buf.append(namespace); buf.append("';\n"); } } catch (Exception e) { SoapUI.logError(e); } return buf.toString(); } public static String createXPath(Node domNode, boolean normalize) { return createXPath(domNode, false, false, false, null, normalize); } public static String createXPath(Node node) { return createXPath(node, false); } public static String createAbsoluteXPath(Node node) { return createXPath(node, false, false, true, null); } public static String createXPath(Node node, boolean anonymous, boolean selectText, XPathModifier modifier) { return createXPath(node, anonymous, selectText, false, modifier); } public static String createXPath(Node node, boolean anonymous, boolean selectText, boolean absolute, XPathModifier modifier) { return createXPath(node, anonymous, selectText, absolute, modifier, false); } public static String createXPath(Node node, boolean anonymous, boolean selectText, boolean absolute, XPathModifier modifier, boolean normalize) { XPathData xpathData = createXPathData(node, anonymous, selectText, absolute, normalize); if (xpathData == null) { return null; } return xpathData.buildXPath(modifier); } public static XPathData createXPathData(Node node, boolean anonymous, boolean selectText, boolean absolute) { return createXPathData(node, anonymous, selectText, absolute, false); } public static XPathData createXPathData(Node node, boolean anonymous, boolean selectText, boolean absolute, boolean normalize) { StringToStringMap nsMap = new StringToStringMap(); List<String> pathComponents = new ArrayList<String>(); int nsCnt = 1; String namespaceURI = node.getNamespaceURI(); if (node.getNodeType() == Node.ATTRIBUTE_NODE) { if (namespaceURI != null && namespaceURI.length() > 0) { String prefix = node.getPrefix(); if (normalize || prefix == null || prefix.length() == 0) { prefix = "ns" + nsCnt++; } nsMap.put(namespaceURI, prefix); pathComponents.add("@" + prefix + ":" + node.getLocalName()); } else { pathComponents.add("@" + node.getLocalName()); } node = ((Attr) node).getOwnerElement(); } else if (node.getNodeType() == Node.DOCUMENT_NODE) { node = ((Document) node).getDocumentElement(); } if (node.getNodeType() == Node.ELEMENT_NODE) { int index = anonymous ? 0 : findNodeIndex(node); String pc; namespaceURI = node.getNamespaceURI(); if (namespaceURI != null && namespaceURI.length() > 0) { String prefix = node.getPrefix(); if (nsMap.containsKey(namespaceURI)) { prefix = nsMap.get(namespaceURI); } else { if (normalize || prefix == null || prefix.length() == 0) { prefix = "ns" + nsCnt++; } while (!nsMap.containsKey(namespaceURI) && nsMap.containsValue(prefix)) { prefix = "ns" + nsCnt++; } nsMap.put(namespaceURI, prefix); } pc = prefix + ":" + node.getLocalName(); } else { pc = node.getLocalName(); } String elementText = XmlUtils.getElementText((Element) node); // not an attribute? if (selectText && pathComponents.isEmpty() && elementText != null && elementText.trim().length() > 0) { pathComponents.add("text()"); } pathComponents.add(pc + ((index == 0) ? "" : "[" + index + "]")); } else { return null; } node = node.getParentNode(); namespaceURI = node.getNamespaceURI(); while (node != null && node.getNodeType() == Node.ELEMENT_NODE && (absolute || (!"Body".equals(node.getNodeName()) && !SoapVersion.Soap11.getEnvelopeNamespace().equals(namespaceURI) && !SoapVersion.Soap12 .getEnvelopeNamespace().equals(namespaceURI)))) { int index = anonymous ? 0 : findNodeIndex(node); String ns = nsMap.get(namespaceURI); String pc; if (ns == null && namespaceURI != null && namespaceURI.length() > 0) { String prefix = node.getPrefix(); if (normalize || prefix == null || prefix.length() == 0) { prefix = "ns" + nsCnt++; } while (!nsMap.containsKey(namespaceURI) && nsMap.containsValue(prefix)) { prefix = "ns" + nsCnt++; } nsMap.put(namespaceURI, prefix); pc = prefix + ":" + node.getLocalName(); } else if (ns != null) { pc = ns + ":" + node.getLocalName(); } else { pc = node.getLocalName(); } pathComponents.add(pc + ((index == 0) ? "" : "[" + index + "]")); node = node.getParentNode(); namespaceURI = node.getNamespaceURI(); } return new XPathData(nsMap, pathComponents, absolute); } private static int findNodeIndex(Node node) { String nm = node.getLocalName(); String ns = node.getNamespaceURI(); short nt = node.getNodeType(); Node parentNode = node.getParentNode(); if (parentNode.getNodeType() != Node.ELEMENT_NODE) { return 1; } Node child = parentNode.getFirstChild(); int ix = 0; while (child != null) { if (child == node) { return ix + 1; } if (child.getNodeType() == nt && nm.equals(child.getLocalName()) && ((ns == null && child.getNamespaceURI() == null) || (ns != null && ns.equals(child .getNamespaceURI())))) { ix++; } child = child.getNextSibling(); } throw new RuntimeException("Child node not found in parent!?"); } public static boolean setNodeValue(Node domNode, String string) { if (domNode == null) { return false; } short nodeType = domNode.getNodeType(); switch (nodeType) { case Node.ELEMENT_NODE: { setElementText((Element) domNode, string); break; } case Node.ATTRIBUTE_NODE: case Node.TEXT_NODE: { domNode.setNodeValue(string); break; } case Node.PROCESSING_INSTRUCTION_NODE: { ((ProcessingInstruction) domNode).setData(string); break; } case Node.CDATA_SECTION_NODE: { ((CDATASection) domNode).setData(string); break; } default: { return false; } } return true; } public static String declareXPathNamespaces(XmlObject xmlObject) { Map<QName, String> map = new HashMap<QName, String>(); XmlCursor cursor = xmlObject.newCursor(); while (cursor.hasNextToken()) { if (cursor.toNextToken().isNamespace()) { map.put(cursor.getName(), cursor.getTextValue()); } } cursor.dispose(); int nsCnt = 0; StringBuilder buf = new StringBuilder(); Set<String> prefixes = new HashSet<String>(); Set<String> usedPrefixes = new HashSet<String>(); for (Map.Entry<QName, String> entry : map.entrySet()) { QName name = entry.getKey(); String prefix = name.getLocalPart(); if (prefix.length() == 0) { prefix = "ns" + Integer.toString(++nsCnt); } else if (prefix.equals("xsd") || prefix.equals("xsi")) { continue; } if (usedPrefixes.contains(prefix)) { int c = 1; while (usedPrefixes.contains(prefix + c)) { c++; } prefix = prefix + Integer.toString(c); } else { prefixes.add(prefix); } buf.append("declare namespace "); buf.append(prefix); buf.append("='"); buf.append(entry.getValue()); buf.append("';\n"); usedPrefixes.add(prefix); } return buf.toString(); } public static String setXPathContent(String xmlText, String xpath, String value) { try { XmlObject xmlObject = XmlObject.Factory.parse(xmlText); String namespaces = declareXPathNamespaces(xmlObject); if (namespaces != null && namespaces.trim().length() > 0) { xpath = namespaces + xpath; } XmlObject[] path = xmlObject.selectPath(xpath); for (XmlObject xml : path) { setNodeValue(xml.getDomNode(), value); } return xmlObject.toString(); } catch (Exception e) { SoapUI.logError(e); } return xmlText; } public static QName getQName(Node node) { if (node == null) { return null; } else if (node.getNamespaceURI() == null) { return new QName(node.getNodeName()); } else { return new QName(node.getNamespaceURI(), node.getLocalName()); } } public static String removeXPathNamespaceDeclarations(String xpath) { while (xpath.startsWith("declare namespace")) { int ix = xpath.indexOf(';'); if (ix == -1) { break; } xpath = xpath.substring(ix + 1).trim(); } return xpath; } public static String stripWhitespaces(String content) { try { XmlObject xml = XmlObject.Factory.parse(content, new XmlOptions().setLoadStripWhitespace() .setLoadStripComments()); content = xml.xmlText(); } catch (Exception e) { SoapUI.logError(e); } return content; } public static NodeList getChildElements(Element elm) { List<Element> list = new ArrayList<Element>(); NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node item = nl.item(c); if (item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE) { list.add((Element) item); } } return new ElementNodeList(list); } public static NodeList getChildElementsByTagName(Element elm, String name) { List<Element> list = new ArrayList<Element>(); NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node item = nl.item(c); if (item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && name.equals(item.getNodeName())) { list.add((Element) item); } } return new ElementNodeList(list); } public static NodeList getChildElementsOfType(Element elm, SchemaType schemaType) { List<Element> list = new ArrayList<Element>(); NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node item = nl.item(c); if (item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && ((Element) item).getAttributeNS(Constants.XSI_NS, "type").endsWith( ":" + schemaType.getName().getLocalPart())) { list.add((Element) item); } } return new ElementNodeList(list); } public static NodeList getChildElementsNS(Element elm, QName name) { return getChildElementsByTagNameNS(elm, name.getNamespaceURI(), name.getLocalPart()); } public static NodeList getChildElementsByTagNameNS(Element elm, String namespaceUri, String localName) { List<Element> list = new ArrayList<Element>(); NodeList nl = elm.getChildNodes(); for (int c = 0; c < nl.getLength(); c++) { Node item = nl.item(c); if (item.getParentNode() == elm && item.getNodeType() == Node.ELEMENT_NODE && localName.equals(item.getLocalName()) && namespaceUri.equals(item.getNamespaceURI())) { list.add((Element) item); } } return new ElementNodeList(list); } public static String serialize(Document document) { StringWriter writer = new StringWriter(); try { serialize(document, writer); } catch (IOException e) { e.printStackTrace(); } return writer.toString(); } public static Element getFirstChildElementNS(Element domNode, QName name) { return getFirstChildElementNS(domNode, name.getNamespaceURI(), name.getLocalPart()); } public static QName findTypeNameForXsiType(String typeName, Element elm) { int ix = typeName.indexOf(':'); if (ix == -1) { return null; } String prefix = typeName.substring(0, ix); String localName = typeName.substring(ix + 1); String namespaceUri = elm.getAttribute("xmlns:" + prefix); if (!StringUtils.hasContent(namespaceUri)) { namespaceUri = findNamespaceForPrefix(elm, prefix); } if (StringUtils.hasContent(namespaceUri)) { return new QName(namespaceUri, localName); } return null; } private static String findNamespaceForPrefix(Element elm, String prefix) { String namespaceUri = null; while (StringUtils.isNullOrEmpty(namespaceUri) && elm != null) { if (elm.getParentNode().getNodeType() != Node.ELEMENT_NODE) { break; } elm = (Element) elm.getParentNode(); namespaceUri = elm.getAttribute("xmlns:" + prefix); } return StringUtils.isNullOrEmpty(namespaceUri) ? null : namespaceUri; } public static String findPrefixForNamespace(Element elm, String namespace) { while (elm != null) { NamedNodeMap attributes = elm.getAttributes(); for (int c = 0; c < attributes.getLength(); c++) { if (attributes.item(c).getNodeValue().equals(namespace) && attributes.item(c).getNodeName().startsWith("xmlns:")) { return attributes.item(c).getNodeName().substring(6); } } if (elm.getParentNode().getNodeType() != Node.ELEMENT_NODE) { break; } elm = (Element) elm.getParentNode(); } return null; } public static void setXsiType(Element elm, QName name) { String prefix = findPrefixForNamespace(elm, name.getNamespaceURI()); if (prefix == null) { prefix = generatePrefixForNamespace(name.getNamespaceURI()); while (findNamespaceForPrefix(elm, prefix) != null) { prefix = generatePrefixForNamespace(name.getNamespaceURI()); } elm.setAttribute("xmlns:" + prefix, name.getNamespaceURI()); } elm.setAttributeNS(Constants.XSI_NS, "type", prefix + ":" + name.getLocalPart()); } private static String generatePrefixForNamespace(String namespaceURI) { return "ns" + (int) (Math.random() * 1000); } public static QName createQName(Node node) { return new QName(node.getNamespaceURI(), node.getLocalName()); } public static Node getNextElementSibling(Node node) { node = node.getNextSibling(); while (node != null && node.getNodeType() != Node.ELEMENT_NODE) { node = node.getNextSibling(); } return node; } public static Document createDocument(QName element) { ensureDocumentBuilder(); Document document = documentBuilder.newDocument(); document.appendChild(document.createElementNS(element.getNamespaceURI(), element.getLocalPart())); return document; } public static String getValueForMatch(XmlCursor cursor) { Node domNode = cursor.getDomNode(); String stringValue; if (domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE) { stringValue = domNode.getNodeValue(); } else if (cursor.getObject() instanceof XmlAnySimpleType) { stringValue = ((XmlAnySimpleType) cursor.getObject()).getStringValue(); } else { if (domNode.getNodeType() == Node.ELEMENT_NODE) { Element elm = (Element) domNode; if (elm.getChildNodes().getLength() == 1 && !hasContentAttributes(elm)) { stringValue = getElementText(elm); } else { stringValue = cursor.getObject().xmlText( new XmlOptions().setSavePrettyPrint().setSaveOuter().setSaveAggressiveNamespaces()); } } else { stringValue = domNode.getNodeValue(); } } return stringValue; } public static boolean hasContentAttributes(Element elm) { NamedNodeMap attributes = elm.getAttributes(); for (int c = 0; c < attributes.getLength(); c++) { Node item = attributes.item(c); String ns = item.getNamespaceURI(); if (!ns.equals(Constants.XML_NS) // && !ns.equals( Constants.XSI_NS ) && !ns.equals( // Constants.XSI_NS_2000 ) // && !ns.equals( Constants.XSD_NS ) ) { return true; } } return false; } public static String getValueForMatch(Node domNode, boolean prettyPrintXml) { String stringValue; if (domNode.getNodeType() == Node.ATTRIBUTE_NODE || domNode.getNodeType() == Node.TEXT_NODE) { stringValue = domNode.getNodeValue(); } else { if (domNode.getNodeType() == Node.ELEMENT_NODE) { Element elm = (Element) domNode; if (elm.getChildNodes().getLength() == 1 && !hasContentAttributes(elm)) { stringValue = getElementText(elm); } else { stringValue = XmlUtils.serialize(domNode, prettyPrintXml); } } else { stringValue = domNode.getNodeValue(); } } return stringValue; } public static String selectFirstNodeValue(XmlObject xmlObject, String xpath) throws XmlException { Node domNode = selectFirstDomNode(xmlObject, xpath); return domNode == null ? null : getNodeValue(domNode); } public static String[] selectNodeValues(XmlObject xmlObject, String xpath) { Node[] nodes = selectDomNodes(xmlObject, xpath); String[] result = new String[nodes.length]; for (int c = 0; c < nodes.length; c++) { result[c] = getNodeValue(nodes[c]); } return result; } public static Node selectFirstDomNode(XmlObject xmlObject, String xpath) { XmlCursor cursor = xmlObject.newCursor(); try { cursor.selectPath(xpath); if (cursor.toNextSelection()) { return cursor.getDomNode(); } else { return null; } } finally { cursor.dispose(); } } public static Node[] selectDomNodes(XmlObject xmlObject, String xpath) { List<Node> result = new ArrayList<Node>(); XmlCursor cursor = xmlObject.newCursor(); try { cursor.selectPath(xpath); while (cursor.toNextSelection()) { result.add(cursor.getDomNode()); } } finally { cursor.dispose(); } return result.toArray(new Node[result.size()]); } private final static class ElementNodeList implements NodeList { private final List<Element> list; public ElementNodeList(List<Element> list) { this.list = list; } public int getLength() { return list.size(); } public Node item(int index) { return list.get(index); } } public static boolean seemsToBeXml(String str) { try { if (StringUtils.isNullOrEmpty(str)) { return false; } XmlObject.Factory.parse(str); return true; } catch (Exception e) { return false; } } public static String extractNamespaces(String xpath) { String result = xpath; int ix = xpath.lastIndexOf("declare namespace"); if (ix != -1) { ix = xpath.indexOf('\'', ix + 1); if (ix != -1) { ix = xpath.indexOf('\'', ix + 1); if (ix != -1) { ix = xpath.indexOf(';'); if (ix != -1) { result = xpath.substring(0, ix + 1); } } } } else { result = ""; } return result; } public static String removeUnneccessaryNamespaces(String xml) { if (StringUtils.isNullOrEmpty(xml)) { return xml; } XmlObject xmlObject; XmlCursor cursor = null; try { xmlObject = XmlObject.Factory.parse(xml); cursor = xmlObject.newCursor(); while (cursor.currentTokenType() != TokenType.START && cursor.currentTokenType() != TokenType.ENDDOC) { cursor.toNextToken(); } if (cursor.currentTokenType() == TokenType.START) { Map<?, ?> nsMap = new HashMap<Object, Object>(); cursor.getAllNamespaces(nsMap); nsMap.remove(cursor.getDomNode().getPrefix()); NamedNodeMap attributes = cursor.getDomNode().getAttributes(); for (int c = 0; attributes != null && c < attributes.getLength(); c++) { nsMap.remove(attributes.item(c).getPrefix()); } if (cursor.toFirstChild()) { while (cursor.getDomNode() != xmlObject.getDomNode()) { attributes = cursor.getDomNode().getAttributes(); for (int c = 0; attributes != null && c < attributes.getLength(); c++) { nsMap.remove(attributes.item(c).getPrefix()); } nsMap.remove(cursor.getDomNode().getPrefix()); cursor.toNextToken(); } } xml = xmlObject.xmlText(new XmlOptions().setSaveOuter().setSavePrettyPrint() .setSaveImplicitNamespaces(nsMap)); } } catch (XmlException e) { } finally { if (cursor != null) { cursor.dispose(); } } return xml; } public static String replaceNameInPathOrQuery(String pathOrQuery, String oldName, String newName) throws Exception { Tokenizer t = new Tokenizer(); t.tokenize(pathOrQuery, 0, -1, 1); StringBuffer result = new StringBuffer(); int lastIx = 0; while (t.currentToken != Token.EOF) { if (t.currentToken == Token.NAME && t.currentTokenValue.equals(oldName)) { result.append(pathOrQuery.substring(lastIx, t.currentTokenStartOffset)); result.append(newName); lastIx = t.currentTokenStartOffset + t.currentTokenValue.length(); } t.next(); } if (lastIx < pathOrQuery.length()) { result.append(pathOrQuery.substring(lastIx)); } // System.out.println("returning " + result.toString()); return result.toString(); } public static QName getQName(XmlObject contentElement) { return contentElement == null ? null : getQName(contentElement.getDomNode()); } public static String getXPathValue(String value, String xpath) { try { XmlObject xmlObject = XmlObject.Factory.parse(value); XmlObject[] nodes = xmlObject.selectPath(xpath); if (nodes.length > 0) { return getNodeValue(nodes[0].getDomNode()); } } catch (Throwable e) { e.printStackTrace(); } return null; } public static String createJdbcXmlResult(Statement statement) throws SQLException, ParserConfigurationException { return createJdbcXmlResultEx(statement, true); } public static String createJdbcXmlResultEx(Statement statement, boolean makeUpperCased) throws SQLException, ParserConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); org.w3c.dom.Document xmlDocumentResult = builder.newDocument(); Element resultsElement = xmlDocumentResult.createElement("Results"); xmlDocumentResult.appendChild(resultsElement); if (statement != null) { try (ResultSet resultSet = statement.getResultSet()) { if (resultSet != null) { resultSet.setFetchSize(statement.getFetchSize()); xmlDocumentResult = addResultSetXmlPart(resultsElement, resultSet, xmlDocumentResult, makeUpperCased); while (statement.getMoreResults()) { try (ResultSet moreResults = statement.getResultSet()) { xmlDocumentResult = addResultSetXmlPart(resultsElement, moreResults, xmlDocumentResult, makeUpperCased); } } } else { Element errorElement = xmlDocumentResult.createElement("UpdateCount"); errorElement.appendChild(xmlDocumentResult.createTextNode(String.valueOf(statement.getUpdateCount()))); resultsElement.appendChild(errorElement); } } } StringWriter out = new StringWriter(); OutputFormat outputFormat = new OutputFormat(xmlDocumentResult); outputFormat.setOmitComments(true); outputFormat.setOmitDocumentType(true); outputFormat.setOmitXMLDeclaration(true); // outputFormat.setLineSeparator( "\n" ); // add this line // // outputFormat.setPreserveSpace( true ); outputFormat.setIndent(3); outputFormat.setIndenting(true); try { XMLSerializer serializer = new XMLSerializer(new PrintWriter(out), outputFormat); serializer.asDOMSerializer(); serializer.serialize(xmlDocumentResult); } catch (IOException e) { SoapUI.logError(e); } return out.toString(); } public static Document addResultSetXmlPart(Element resultsElement, ResultSet rs, Document xmlDocumentResult, boolean uppercase) throws SQLException { final String TABLE_COLUMN_DELIMITER = "."; ResultSetMetaData rsmd = rs.getMetaData(); Element resultSetElement = xmlDocumentResult.createElement("ResultSet"); resultSetElement.setAttribute("fetchSize", String.valueOf(rs.getFetchSize())); resultsElement.appendChild(resultSetElement); int colCount = rsmd.getColumnCount(); while (rs.next()) { Element rowElement = xmlDocumentResult.createElement("Row"); rowElement.setAttribute("rowNumber", String.valueOf(rs.getRow())); resultsElement.appendChild(rowElement); for (int i = 1; i <= colCount; i++) { StringBuffer resultColumnName = new StringBuffer(); String tableName = rsmd.getTableName(i); String columnName = rsmd.getColumnName(i); if (uppercase) { tableName = tableName.toUpperCase(); columnName = columnName.toUpperCase(); } if (StringUtils.hasContent(tableName)) { resultColumnName.append(tableName); resultColumnName.append(TABLE_COLUMN_DELIMITER); } resultColumnName.append(columnName); String xmlName = StringUtils.createXmlName(resultColumnName.toString()); Element node = xmlDocumentResult.createElement(xmlName); String value = rs.getString(i); if (StringUtils.hasContent(value)) { Text textNode = xmlDocumentResult.createTextNode(value); node.appendChild(textNode); } rowElement.appendChild(node); } resultSetElement.appendChild(rowElement); } return xmlDocumentResult; } }