| /* |
| * 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.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| 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 Log __log = LogFactory.getLog(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()); |
| } |
| |
| } |