blob: 6df7cbf700616583266a7e27777fcf9902d2e3f1 [file] [log] [blame]
/*
* 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());
}
}