/* * 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.ode.il; import java.io.IOException; import java.util.Iterator; import java.util.Map; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamConstants; import javax.xml.transform.Source; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMContainer; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.OMNode; import org.apache.axiom.om.OMText; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.ode.utils.DOMUtils; import org.apache.ode.utils.NSContext; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.InputSource; /** * Utility methods to convert from/to AxiOM and DOM. */ public class OMUtils { private static Logger __log = LoggerFactory.getLogger(OMUtils.class); public static OMElement getFirstChildWithName(OMElement parent, String name) { if (parent == null) throw new IllegalArgumentException("null parent"); if (name == null) throw new IllegalArgumentException("null name"); for (Iterator it = parent.getChildElements(); it.hasNext();) { OMElement e = (OMElement) it.next(); if (name.equals(e.getQName().getLocalPart())) return e; } return null; } public static Element toDOM(OMElement element) { return toDOM(element, DOMUtils.newDocument()); } public static Element toDOM(OMElement element, Document doc) { return toDOM(element,doc,true); } @SuppressWarnings("unchecked") public static Element toDOM(OMElement element, Document doc, boolean deepNS) { // // Fix regarding lost qnames on response of invoke activity: // * copy an element including its prefix. // * add all namespase attributes. // String domElementNsUri = element.getQName().getNamespaceURI(); String domElementQName; if (element.getQName().getPrefix() == null || element.getQName().getPrefix().trim().length() == 0) { domElementQName = element.getQName().getLocalPart(); } else { domElementQName = element.getQName().getPrefix() + ":" + element.getQName().getLocalPart(); } if (__log.isTraceEnabled()) __log.trace("toDOM: creating element with nsUri=" + domElementNsUri + " qname=" + domElementQName + " from omElement, name=" + element.getLocalName()); final Element domElement = doc.createElementNS( domElementNsUri, domElementQName); if (deepNS) { NSContext nscontext = new NSContext(); buildNScontext(nscontext, element); DOMUtils.injectNamespacesWithAllPrefixes(domElement,nscontext); } else { if (element.getAllDeclaredNamespaces() != null) { for (Iterator<OMNamespace> i = element.getAllDeclaredNamespaces(); i.hasNext(); ) { OMNamespace omns = i.next(); if (omns.getPrefix().equals("")) domElement.setAttributeNS(DOMUtils.NS_URI_XMLNS, "xmlns", omns.getNamespaceURI() == null ? "" : omns.getNamespaceURI()); else domElement.setAttributeNS(DOMUtils.NS_URI_XMLNS, "xmlns:"+ omns.getPrefix(), omns.getNamespaceURI()); } } } if (__log.isTraceEnabled()) __log.trace("toDOM: created root element (deepNS=" + deepNS + "): " + DOMUtils.domToString(domElement)); for (Iterator i = element.getAllAttributes(); i.hasNext();) { final OMAttribute attr = (OMAttribute) i.next(); Attr newAttr; if (attr.getNamespace() != null) newAttr = doc.createAttributeNS(attr.getNamespace().getNamespaceURI(), attr.getLocalName()); else newAttr = doc.createAttributeNS(null,attr.getLocalName()); newAttr.appendChild(doc.createTextNode(attr.getAttributeValue())); domElement.setAttributeNodeNS(newAttr); // Case of qualified attribute values, we're forced to add corresponding namespace declaration manually... int colonIdx = attr.getAttributeValue().indexOf(":"); if (colonIdx > 0) { OMNamespace attrValNs = element.findNamespaceURI(attr.getAttributeValue().substring(0, colonIdx)); if (attrValNs != null) domElement.setAttributeNS(DOMUtils.NS_URI_XMLNS, "xmlns:"+ attrValNs.getPrefix(), attrValNs.getNamespaceURI()); } } for (Iterator<OMNode> i = element.getChildren(); i.hasNext();) { OMNode omn = i.next(); switch (omn.getType()) { case OMNode.CDATA_SECTION_NODE: domElement.appendChild(doc.createCDATASection(((OMText)omn).getText())); break; case OMNode.TEXT_NODE: domElement.appendChild(doc.createTextNode(((OMText)omn).getText())); break; case OMNode.ELEMENT_NODE: domElement.appendChild(toDOM((OMElement)omn,doc, false)); break; } } return domElement; } @SuppressWarnings("unchecked") private static void buildNScontext(NSContext nscontext, OMElement element) { if (element == null) return; if (element.getParent() instanceof OMElement) buildNScontext(nscontext, (OMElement) element.getParent()); if (element.getAllDeclaredNamespaces() != null) for (Iterator<OMNamespace> i=element.getAllDeclaredNamespaces(); i.hasNext(); ){ OMNamespace omn = i.next(); nscontext.register(omn.getPrefix(), omn.getNamespaceURI()); } if (element.getDefaultNamespace() != null) nscontext.register("", element.getDefaultNamespace().getNamespaceURI()); } public static OMElement toOM(Element src, OMFactory omf) { return toOM(src,omf,null); } public static OMElement toOM(Element src, OMFactory omf, OMContainer parent) { OMNamespace namespace = null; String srcPrefix = src.getPrefix(); String srcNamespaceURI = src.getNamespaceURI(); //AXIOM 1.2.13 doesn't allow setting of default namespace unless a namespace has been associated with the OMElement at object creation, //hence create the namespace first and use it during OMElement creation. //Avoid using declareDefaultNamespace() as it's found to be adding an empty namespaceURI in some cases. if (srcNamespaceURI != null) { //if no prefix then it's default namespace if(srcPrefix == null) srcPrefix = ""; namespace = omf.createOMNamespace(srcNamespaceURI, srcPrefix); } OMElement omElement = parent == null ? omf.createOMElement(src.getLocalName(), namespace) : omf.createOMElement(src.getLocalName(), namespace, parent); if (parent == null) { NSContext nscontext = DOMUtils.getMyNSContext(src); injectNamespaces(omElement,nscontext.toMap(),omf); } else { Map<String,String> nss = DOMUtils.getMyNamespaces(src); injectNamespaces(omElement, nss,omf); } NamedNodeMap attrs = src.getAttributes(); for (int i = 0; i <attrs.getLength(); ++i) { Attr attr = (Attr)attrs.item(i); if (attr.getLocalName().equals("xmlns") || (attr.getNamespaceURI() != null && attr.getNamespaceURI().equals(DOMUtils.NS_URI_XMLNS))) continue; OMNamespace attrOmNs = null; String attrNs = attr.getNamespaceURI(); String attrPrefix = attr.getPrefix(); if (attrNs != null) attrOmNs = omElement.findNamespace(attrNs,null); if (attrOmNs == null && attrPrefix != null) attrOmNs = omElement.findNamespace(null, attrPrefix); omElement.addAttribute(attr.getLocalName(), attr.getValue(), attrOmNs); } NodeList children = src.getChildNodes(); for (int i = 0 ; i < children.getLength(); ++i) { Node n = children.item(i); switch (n.getNodeType()) { case Node.CDATA_SECTION_NODE: omElement.addChild(omf.createOMText(((CDATASection)n).getTextContent(),XMLStreamConstants.CDATA)); break; case Node.TEXT_NODE: omElement.addChild(omf.createOMText(((Text)n).getTextContent(),XMLStreamConstants.CHARACTERS)); break; case Node.ELEMENT_NODE: toOM((Element)n,omf,omElement); break; } } return omElement; } private static void injectNamespaces(OMElement omElement, Map<String,String> nscontext,OMFactory omf) { for (String prefix : nscontext.keySet()) { String uri = nscontext.get(prefix); if (prefix.equals("")) omElement.declareNamespace(omf.createOMNamespace(uri, "")); else omElement.declareNamespace(uri, prefix); } } /** * Axiom is supposed to handle this properly however this method is buggy and doesn't work (whereas setting a QName as text * works). * * @param elmt * @return text qname */ public static QName getTextAsQName(OMElement elmt) { QName qname = elmt.getTextAsQName(); // The getTextAsQName is buggy, it sometimes return the full text without extracting namespace if (qname == null || qname.getNamespaceURI().length() == 0) { int colonIdx = elmt.getText().indexOf(":"); String localpart = elmt.getText().substring(colonIdx + 1, elmt.getText().length()); String prefix = elmt.getText().substring(0, colonIdx); String ns = elmt.findNamespaceURI(prefix).getNamespaceURI(); qname = new QName(ns, localpart, prefix); } return qname; } /** * Parse an XML document located using an {@link InputSource} using the * pooled document builder. */ public static OMElement toOM(Source inputSource) throws IOException { Document doc = DOMUtils.sourceToDOM(inputSource); return toOM(doc.getDocumentElement(), OMAbstractFactory.getOMFactory()); } }