org.eclipse.persistence.internal.oxm.SAXFragmentBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 2024 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.oxm;
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord;
import org.eclipse.persistence.platform.xml.SAXDocumentBuilder;
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 java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @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;
}
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
if (!mixedContent) {
boolean bufferContainsOnlyWhitespace = stringBuffer.toString().trim().isEmpty();
if (bufferContainsOnlyWhitespace) {
stringBuffer.reset();
}
}
if ((!stringBuffer.isEmpty()) && !(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.isEmpty()) {
namespaceURI = null;
}
if(qName == null){
qName = localName;
if(namespaceURI != null){
if(owningRecord != null){
String prefix = owningRecord.resolveNamespaceUri(namespaceURI);
if(prefix != null && !prefix.isEmpty()){
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.isEmpty()){
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.isEmpty()) {
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.isEmpty()) {
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);
}
}
}
@Override
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.isEmpty()) {
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.isEmpty()) {
Text text = getInitializedDocument().createTextNode(stringBuffer.toString());
endedElement.appendChild(text);
stringBuffer.reset();
}
} else {
super.endElement(namespaceURI, localName, qName);
}
}
public List getNodes() {
return super.nodes;
}
public void setOwningRecord(UnmarshalRecord record) {
this.owningRecord = record;
}
@Override
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.
*/
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;
}
}