/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.oxm; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord; import org.eclipse.persistence.platform.xml.XMLPlatform; import org.eclipse.persistence.platform.xml.XMLPlatformFactory; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.eclipse.persistence.platform.xml.SAXDocumentBuilder; /** * @version $Header: SAXFragmentBuilder.java 18-sep-2007.14:36:11 dmahar Exp $ * @author mmacivor * @since release specific (what release of product did this appear in) */ public class SAXFragmentBuilder extends SAXDocumentBuilder { private UnmarshalRecord owningRecord; private boolean mixedContent; public SAXFragmentBuilder(UnmarshalRecord unmarshalRecord) { super(); owningRecord = unmarshalRecord; } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { if (!mixedContent) { boolean bufferContainsOnlyWhitespace = stringBuffer.toString().trim().length() == 0; if (bufferContainsOnlyWhitespace) { stringBuffer.reset(); } } if ((stringBuffer.length() > 0) && !(nodes.size() == 1)) { Text text = getInitializedDocument().createTextNode(stringBuffer.toString()); Node parent = this.nodes.get(nodes.size() - 1); parent.appendChild(text); processNamespacesForText(text.getTextContent(), (Element)parent); stringBuffer.reset(); } if (null != namespaceURI && namespaceURI.length() == 0) { namespaceURI = null; } if(qName == null){ qName = localName; if(namespaceURI != null){ if(owningRecord != null){ String prefix = owningRecord.resolveNamespaceUri(namespaceURI); if(prefix != null && prefix.length() > 0){ qName = prefix +Constants.COLON+ qName; } } } } int qNameColonIndex = qName.indexOf(Constants.COLON); if ((namespaceURI != null) && (qNameColonIndex == -1)) { //check for a prefix from the unmarshal record: String prefix = owningRecord.resolveNamespaceUri(namespaceURI); if (prefix != null && prefix.length() >0){ qName = prefix + Constants.COLON + qName; qNameColonIndex = prefix.length(); } } Element element = getInitializedDocument().createElementNS(namespaceURI, qName); Node parentNode = nodes.get(nodes.size() - 1); appendChildNode(parentNode, element); nodes.add(element); if (qNameColonIndex > -1) { String prefix = qName.substring(0, qNameColonIndex); String parentUri = null; if (element.getParentNode() != null) { parentUri = XMLPlatformFactory.getInstance().getXMLPlatform().resolveNamespacePrefix(element.getParentNode(), prefix); } if ((parentUri == null) || parentUri.length() == 0) { startPrefixMapping(prefix, namespaceURI); } } if (null != namespaceDeclarations) { Iterator namespaces = namespaceDeclarations.entrySet().iterator(); while (namespaces.hasNext()) { Map.Entry entry = (Map.Entry)namespaces.next(); addNamespaceDeclaration(element, (String)entry.getKey(), (String)entry.getValue()); } namespaceDeclarations = null; } int numberOfAttributes = atts.getLength(); String attributeNamespaceURI, attributeQName, attributeValue; for (int x = 0; x < numberOfAttributes; x++) { attributeNamespaceURI = atts.getURI(x); attributeQName = atts.getQName(x); attributeValue = atts.getValue(x); // Empty string will be treated as a null URI if (null != attributeNamespaceURI && attributeNamespaceURI.length() == 0) { attributeNamespaceURI = null; } // Handle case where prefix/uri are not set on an xmlns prefixed attribute if (attributeNamespaceURI == null && attributeQName.startsWith(javax.xml.XMLConstants.XMLNS_ATTRIBUTE)) { attributeNamespaceURI = javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI; } element.setAttributeNS(attributeNamespaceURI, attributeQName, attributeValue == null ? Constants.EMPTY_STRING : attributeValue); if (attributeValue != null) { processNamespacesForText(attributeValue, element); } } } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (super.nodes.size() == 2) { Element endedElement = (Element)nodes.get(nodes.size() -1); if (stringBuffer.length() > 0) { Text text = getInitializedDocument().createTextNode(stringBuffer.toString()); endedElement.appendChild(text); stringBuffer.reset(); processNamespacesForText(text.getTextContent(), endedElement); } while(owningRecord.isSelfRecord() && owningRecord.getParentRecord() != null){ owningRecord = owningRecord.getParentRecord(); } //just the doc left in the stack. Finish this off. owningRecord.getXMLReader().setContentHandler(owningRecord); owningRecord.endElement(namespaceURI, localName, qName); } else { super.endElement(namespaceURI, localName, qName); } } public void endSelfElement(String namespaceURI, String localName, String qName) throws SAXException { if (super.nodes.size() == 2) { Element endedElement = (Element)nodes.get(nodes.size() -1); if (stringBuffer.length() > 0) { Text text = getInitializedDocument().createTextNode(stringBuffer.toString()); endedElement.appendChild(text); stringBuffer.reset(); } } else { super.endElement(namespaceURI, localName, qName); } } public List<Node> getNodes() { return super.nodes; } public void setOwningRecord(UnmarshalRecord record) { this.owningRecord = record; } public void appendChildNode(Node parent, Node child) { if (parent != this.getDocument()) { parent.appendChild(child); } } public Attr buildAttributeNode(String namespaceURI, String localName, String value) { try { Attr attribute = getInitializedDocument().createAttributeNS(namespaceURI, localName); attribute.setValue(value); return attribute; } catch (SAXException ex) { } return null; } public Text buildTextNode(String textValue) { try { Text text = getInitializedDocument().createTextNode(textValue); return text; } catch (SAXException ex) { } return null; } /** * Adds a namespace declaration to the parent element if the textValue represents a * prefixed qualified name. The determination of a qname is based on the existance of a * colon character and the ability to resolve the characters before the colon to a * namespace uri. * @param textValue * @param parentNode */ private void processNamespacesForText(String textValue, Element parentNode) { //If the text value is a qname, we may need to do namespace processing int colon = textValue.indexOf(':'); if(colon != -1) { String prefix = textValue.substring(0, colon); XMLPlatform platform = XMLPlatformFactory.getInstance().getXMLPlatform(); String uri = platform.resolveNamespacePrefix(parentNode, prefix); if(uri == null) { uri = this.owningRecord.resolveNamespacePrefix(prefix); if(uri != null) { //add namespace declaration addNamespaceDeclaration(parentNode, prefix, uri); } } } } public void setMixedContent(boolean mixedContent) { this.mixedContent = mixedContent; } }