| /* |
| * Copyright (c) 1998, 2021 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 java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Vector; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.exceptions.ConversionException; |
| import org.eclipse.persistence.exceptions.XMLMarshalException; |
| import org.eclipse.persistence.internal.core.helper.CoreClassConstants; |
| import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; |
| import org.eclipse.persistence.internal.oxm.documentpreservation.NoDocumentPreservationPolicy; |
| import org.eclipse.persistence.internal.oxm.documentpreservation.XMLBinderPolicy; |
| import org.eclipse.persistence.internal.oxm.mappings.Field; |
| import org.eclipse.persistence.internal.oxm.mappings.UnionField; |
| import org.eclipse.persistence.internal.oxm.record.XMLRecord; |
| import org.eclipse.persistence.oxm.NamespaceResolver; |
| import org.eclipse.persistence.oxm.XMLField; |
| import org.eclipse.persistence.oxm.documentpreservation.DocumentPreservationPolicy; |
| import org.eclipse.persistence.oxm.record.XMLEntry; |
| import org.eclipse.persistence.platform.xml.XMLNodeList; |
| 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; |
| |
| /** |
| * INTERNAL: |
| * <p><b>Purpose</b>: Utility class for creating and removing XML nodes using |
| * XPath expressions.</p> |
| * @author Rick Barkhouse - rick.barkhouse@oracle.com |
| * @since OracleAS TopLink 10<i>g</i> (10.0.3), 03/11/2003 10:21:42 |
| */ |
| public class XPathEngine < |
| XML_FIELD extends Field |
| >{ |
| private static XPathEngine instance = null; |
| private UnmarshalXPathEngine unmarshalXPathEngine; |
| private DocumentPreservationPolicy noDocPresPolicy = new NoDocumentPreservationPolicy();//handles xpath engine calls without a policy |
| private DocumentPreservationPolicy xmlBinderPolicy = new XMLBinderPolicy();//used for adding new elements to a collection. |
| |
| /** |
| * Return the <code>XPathEngine</code> singleton. |
| */ |
| public static XPathEngine getInstance() { |
| if (instance == null) { |
| instance = new XPathEngine(); |
| } |
| return instance; |
| } |
| |
| private XPathEngine() { |
| super(); |
| unmarshalXPathEngine = new UnmarshalXPathEngine(); |
| } |
| |
| /** |
| * Create the node path specified by <code>xpathString</code> under <code>element</code>. |
| * This method also supports creating attributes and indexed elements using the appropriate |
| * XPath syntax ('<code>@</code>' and '<code>[ ]</code>' respectively). |
| * |
| * @param xmlField XMLField containing xpath expression representing the node path to create |
| * @param element Root element under which to create path |
| * |
| * @return The last <code>XMLNode</code> in the path |
| * |
| * @exception XMLMarshalException Thrown if passed an invalid XPath string |
| */ |
| public Node create(Field xmlField, Node element, CoreAbstractSession session) throws XMLMarshalException { |
| return create(xmlField, element, this, session); |
| } |
| |
| public Node create(Field xmlField, Node element, Object value, CoreAbstractSession session) { |
| return create(xmlField, element, value, null, noDocPresPolicy, session); |
| } |
| |
| /** |
| * Create the node path specified by <code>xpathString</code> under <code>element</code> |
| * and initialize the leaf node with <code>value</code>. |
| * This method also supports creating attributes and integer-indexed elements using the |
| * appropriate XPath syntax ('<code>@</code>' and '<code>[ ]</code>' respectively). |
| * |
| * @param xmlField XMLField containing xpath expression representing the node path to create |
| * @param element Root element under which to create path |
| * @param value Initial value for the leaf node (should not be a list) |
| * |
| * @return The last <code>XMLNode</code> in the path |
| * |
| * @exception XMLMarshalException Thrown if passed an invalid XPath string |
| */ |
| public Node create(Field xmlField, Node element, Object value, Field lastUpdated, DocumentPreservationPolicy docPresPolicy, CoreAbstractSession session) throws XMLMarshalException { |
| if (null == value) { |
| return null; |
| } |
| if (docPresPolicy == null) { |
| //EIS case and others |
| docPresPolicy = this.noDocPresPolicy; |
| } |
| XPathFragment fragment = xmlField.getXPathFragment(); |
| if (fragment.getNextFragment() == null) { |
| if (fragment.nameIsText()) { |
| Object textValue = getValueToWrite(value, xmlField, session); |
| if (textValue instanceof String) { |
| if (xmlField.isTypedTextField()) { |
| XMLNodeList createdElements = new XMLNodeList(); |
| createdElements.add(element); |
| addTypeAttributes(createdElements, xmlField, value, resolveNamespacePrefixForURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, getNamespaceResolverForField(xmlField)), session); |
| } |
| return addText(xmlField, element, (String)textValue); |
| } |
| return null; |
| } |
| } |
| NodeList created = createCollection(xmlField, element, value, lastUpdated, docPresPolicy, session); |
| |
| if ((created == null) || (created.getLength() == 0)) { |
| return null; |
| } |
| |
| return created.item(0); |
| } |
| |
| public void create(List<Field> xmlFields, Node contextNode, List<XMLEntry> values, Field lastUpdatedField, DocumentPreservationPolicy docPresPolicy, CoreAbstractSession session) { |
| List itemsToWrite = new ArrayList(); |
| for(int i = 0, size = values.size(); i < size; i++) { |
| XMLEntry nextEntry = values.get(i); |
| itemsToWrite.add(nextEntry.getValue()); |
| if(i == (values.size() -1) || values.get(i+1).getXMLField() != nextEntry.getXMLField()) { |
| create(nextEntry.getXMLField(), contextNode, itemsToWrite, lastUpdatedField, docPresPolicy, session); |
| itemsToWrite = new ArrayList(); |
| lastUpdatedField = nextEntry.getXMLField(); |
| } |
| } |
| } |
| |
| |
| |
| /** |
| * Create the node path specified by <code>xpathString</code> under <code>element</code> |
| * and initialize the leaf node with <code>value</code>. |
| * This method also supports creating attributes and integer-indexed elements using the |
| * appropriate XPath syntax ('<code>@</code>' and '<code>[ ]</code>' respectively). |
| * |
| * @param xmlField XMLField containing xpath expression representing the node path to create |
| * @param element Root element under which to create path |
| * @param value Initial value for the leaf node (this can be a value or a collection of values) |
| * |
| * @return The last <code>XMLNode</code> in the path |
| * |
| * @throws XMLMarshalException Thrown if passed an invalid XPath string |
| */ |
| private NodeList createCollection(Field xmlField, Node element, Object value, Field lastUpdated, DocumentPreservationPolicy docPresPolicy, CoreAbstractSession session) throws XMLMarshalException { |
| XMLNodeList createdElements = new XMLNodeList(); |
| |
| //CR:### If the value is null, then the node(s) must not be created. |
| if ((value == null) || (value instanceof Collection && (((Collection)value).size() == 0))) { |
| return createdElements; |
| } |
| Node nextElement = element; |
| Element sibling = null; |
| XPathFragment siblingFragment = null; |
| if(lastUpdated != null) { |
| siblingFragment = lastUpdated.getXPathFragment(); |
| } |
| if ((lastUpdated != null) && !siblingFragment.isAttribute() && !siblingFragment.nameIsText()) { |
| //find the sibling element. |
| NodeList nodes = unmarshalXPathEngine.selectElementNodes(element, siblingFragment, getNamespaceResolverForField(lastUpdated)); |
| if (nodes.getLength() > 0) { |
| sibling = (Element)nodes.item(nodes.getLength() - 1); |
| } |
| } |
| NodeList elements; |
| XPathFragment next = xmlField.getXPathFragment(); |
| while (next != null) { |
| if (next.isAttribute()) { |
| addAttribute(next, xmlField, nextElement, value, session); |
| } else if (next.containsIndex()) { |
| // If we are creating multiple nodes from this XPath, assume the value is for the last node. |
| boolean hasMore = !(next.getHasText() || (next.getNextFragment() == null)); |
| |
| if (hasMore) { |
| nextElement = addIndexedElement(next, xmlField, nextElement, this, !hasMore, session); |
| } else { |
| Object valueToWrite = getValueToWrite(value, xmlField, session); |
| nextElement = addIndexedElement(next, xmlField, nextElement, valueToWrite, !hasMore, session); |
| createdElements.add(nextElement); |
| } |
| } else { |
| boolean hasMore = !(next.getHasText() || (next.getNextFragment() == null)); |
| |
| if (hasMore) { |
| elements = addElements(next, xmlField, nextElement, this, !hasMore, sibling, docPresPolicy, session); |
| } else { |
| XPathFragment nextFragment = next.getNextFragment(); |
| if ((nextFragment != null) && nextFragment.isAttribute() && !(value instanceof List)) { |
| elements = addElements(next, xmlField, nextElement, this, hasMore, sibling, docPresPolicy, session); |
| } else { |
| Object valueToWrite = getValueToWrite(value, xmlField, session); |
| elements = addElements(next, xmlField, nextElement, valueToWrite, !hasMore, sibling, docPresPolicy, session); |
| createdElements.addAll(elements); |
| } |
| } |
| |
| nextElement = elements.item(elements.getLength() - 1); |
| } |
| if(siblingFragment != null && sibling != null && siblingFragment.equals(next)) { |
| //if the sibling shares a grouping element, update the sibling |
| siblingFragment = siblingFragment.getNextFragment(); |
| if ((siblingFragment != null) && !siblingFragment.isAttribute() && !siblingFragment.nameIsText()) { |
| //find the sibling element. |
| NodeList nodes = unmarshalXPathEngine.selectElementNodes(nextElement, siblingFragment, getNamespaceResolverForField(lastUpdated)); |
| if (nodes.getLength() > 0) { |
| sibling = (Element)nodes.item(nodes.getLength() - 1); |
| } else { |
| sibling = null; |
| } |
| } else { |
| sibling = null; |
| } |
| } else { |
| sibling = null; |
| } |
| |
| next = next.getNextFragment(); |
| if ((next != null) && next.nameIsText()) { |
| next = null; |
| } |
| } |
| |
| if (xmlField.isTypedTextField()) { |
| addTypeAttributes(createdElements, xmlField, value, resolveNamespacePrefixForURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, getNamespaceResolverForField(xmlField)), session); |
| } |
| |
| return createdElements; |
| } |
| |
| private Object getNonNodeValueToWrite(Object value, Field xmlField, CoreAbstractSession session) { |
| if (this == value) { |
| return this; |
| } |
| |
| QName schemaType = null; |
| if(xmlField.getLeafElementType() != null){ |
| schemaType = xmlField.getLeafElementType(); |
| }else if (xmlField.isUnionField()) { |
| return getValueToWriteForUnion((UnionField)xmlField, value, session); |
| }else if (xmlField.isTypedTextField()) { |
| ConversionManager conversionManager = (ConversionManager) session.getDatasourcePlatform().getConversionManager(); |
| schemaType = xmlField.getXMLType(value.getClass(), conversionManager); |
| }else if (xmlField.getSchemaType() != null) { |
| schemaType = xmlField.getSchemaType(); |
| } |
| |
| if (value instanceof List) { |
| if (xmlField.usesSingleNode()) { |
| StringBuilder returnStringBuilder = new StringBuilder(); |
| for (int i = 0; i < ((List)value).size(); i++) { |
| Object nextItem = ((List)value).get(i); |
| |
| String nextConvertedItem = null; |
| if(schemaType != null && schemaType.equals(Constants.QNAME_QNAME)){ |
| nextConvertedItem = getStringForQName((QName)nextItem, getNamespaceResolverForField(xmlField)); |
| }else{ |
| nextConvertedItem = ((ConversionManager)session.getDatasourcePlatform().getConversionManager()).convertObject(nextItem, CoreClassConstants.STRING, schemaType); |
| } |
| returnStringBuilder.append(nextConvertedItem); |
| if (i < (((List)value).size() - 1)) { |
| returnStringBuilder.append(' '); |
| } |
| } |
| return returnStringBuilder.toString(); |
| } else { |
| ArrayList items = new ArrayList(((List)value).size()); |
| for (int index = 0; index < ((List)value).size(); index++) { |
| Object nextItem = ((List)value).get(index); |
| if (nextItem instanceof Node || nextItem == XMLRecord.NIL) { |
| items.add(nextItem); |
| } else { |
| if(schemaType != null && schemaType.equals(Constants.QNAME_QNAME)){ |
| String nextConvertedItem = getStringForQName((QName)nextItem, getNamespaceResolverForField(xmlField)); |
| items.add(nextConvertedItem); |
| }else{ |
| String nextConvertedItem = ((ConversionManager)session.getDatasourcePlatform().getConversionManager()).convertObject(nextItem, CoreClassConstants.STRING, schemaType); |
| items.add(nextConvertedItem); |
| } |
| } |
| } |
| return items; |
| } |
| } else { |
| if(schemaType != null && schemaType.equals(Constants.QNAME_QNAME)){ |
| return getStringForQName((QName)value, getNamespaceResolverForField(xmlField)); |
| } |
| return ((ConversionManager)session.getDatasourcePlatform().getConversionManager()).convertObject(value, CoreClassConstants.STRING, schemaType); |
| } |
| } |
| |
| private Object getValueToWrite(Object value, Field xmlField, CoreAbstractSession session) { |
| if (value instanceof Node || value == XMLRecord.NIL) { |
| return value; |
| } |
| |
| return getNonNodeValueToWrite(value, xmlField, session); |
| } |
| |
| private String getSingleValueToWriteForUnion(UnionField xmlField, Object value, CoreAbstractSession session) { |
| List schemaTypes = xmlField.getSchemaTypes(); |
| QName schemaType = null; |
| for (int i = 0; i < schemaTypes.size(); i++) { |
| QName nextQName = (QName)(xmlField).getSchemaTypes().get(i); |
| try { |
| if (nextQName != null) { |
| ConversionManager conversionManager = (ConversionManager)session.getDatasourcePlatform().getConversionManager(); |
| Class javaClass = xmlField.getJavaClass(nextQName, conversionManager); |
| value = conversionManager.convertObject(value, javaClass, nextQName); |
| schemaType = nextQName; |
| break; |
| } |
| } catch (ConversionException ce) { |
| if (i == (schemaTypes.size() - 1)) { |
| schemaType = nextQName; |
| } |
| } |
| } |
| return ((ConversionManager)session.getDatasourcePlatform().getConversionManager()).convertObject(value, CoreClassConstants.STRING, schemaType); |
| } |
| |
| private Object getValueToWriteForUnion(UnionField xmlField, Object value, CoreAbstractSession session) { |
| if (value instanceof List) { |
| if (xmlField.usesSingleNode()) { |
| StringBuilder returnStringBuilder = new StringBuilder(); |
| Object next = null; |
| for (int i = 0; i < ((List)value).size(); i++) { |
| next = ((List)value).get(i); |
| returnStringBuilder.append(getSingleValueToWriteForUnion(xmlField, next, session)); |
| if (i < (((List)value).size() - 1)) { |
| returnStringBuilder.append(' '); |
| } |
| } |
| return returnStringBuilder.toString(); |
| } else { |
| ArrayList items = new ArrayList(((List)value).size()); |
| Object next = null; |
| for (int i = 0; i < ((List)value).size(); i++) { |
| next = ((List)value).get(i); |
| items.add(getSingleValueToWriteForUnion(xmlField, next, session)); |
| } |
| return items; |
| } |
| } else { |
| return getSingleValueToWriteForUnion(xmlField, value, session); |
| } |
| } |
| |
| /** |
| * Add a new indexed <code>element</code> to the <code>parent</code> element. |
| * Will overwrite if an element already exists at that position. Currently only supports |
| * integer indices. |
| * |
| * @param fragment element and index to create (in the form 'element[index]') |
| * @param parent Parent element |
| * @param value Value for the new node |
| * @param forceCreate If true, create a new element even if one with the same name currently exists |
| * |
| * @return The <code>XMLElement</code> that was created/found |
| * |
| * @throws XMLMarshalException Thrown if passed an invalid XPath string |
| */ |
| private Node addIndexedElement(XPathFragment fragment, Field xmlField, Node parent, Object value, boolean forceCreate, CoreAbstractSession session) throws XMLMarshalException { |
| String element = fragment.getShortName(); |
| |
| int index = fragment.getIndexValue(); |
| if (index < 0) { |
| throw XMLMarshalException.invalidXPathIndexString(fragment.getXPath()); |
| } |
| |
| Node existingElement; |
| NamespaceResolver namespaceResolver = getNamespaceResolverForField(xmlField); |
| for (int i = 1; i < index; i++) { |
| Field<XMLConversionManager, NamespaceResolver> field = new XMLField(element + "[" + i + "]"); |
| field.setNamespaceResolver(namespaceResolver); |
| existingElement = (Node)unmarshalXPathEngine.selectSingleNode(parent, field, namespaceResolver); |
| if (existingElement == null) { |
| addElement(new XPathFragment(element), xmlField, parent, this, true, session); |
| } |
| } |
| Field<XMLConversionManager, NamespaceResolver> field = new XMLField(fragment.getXPath()); |
| field.setNamespaceResolver(namespaceResolver); |
| existingElement = (Node)unmarshalXPathEngine.selectSingleNode(parent, field, namespaceResolver); |
| if (existingElement == null) { |
| return addElement(new XPathFragment(element), field, parent, value, true, session); |
| } |
| |
| if (!forceCreate) { |
| return existingElement; |
| } |
| |
| String namespace = resolveNamespacePrefix(fragment, namespaceResolver); |
| Element elementToReturn = parent.getOwnerDocument().createElementNS(namespace, element); |
| |
| if ((value != this) && (value != null)) { |
| if (value instanceof String) { |
| addText(xmlField, elementToReturn, (String)value); |
| } |
| } |
| parent.replaceChild(elementToReturn, existingElement); |
| return elementToReturn; |
| } |
| |
| /** |
| * Add a new <code>element</code> to the <code>parent</code> element. If an element with |
| * this name already exists, return it (unless <code>forceCreate</code> is <code>true</code>). |
| * |
| * @param fragment Name of element to create |
| * @param parent Parent element |
| * @param value Value for the new node |
| * @param forceCreate If true, create a new element even if one with the same name currently exists |
| * |
| * @return The <code>XMLElement</code> that was created/found |
| */ |
| private Node addElement(XPathFragment fragment, Field xmlField, Node parent, Object value, boolean forceCreate, CoreAbstractSession session) { |
| return addElement(fragment, xmlField, parent, null, value, forceCreate, session); |
| } |
| |
| private Node addElement(XPathFragment fragment, Field xmlField, Node parent, QName schemaType, Object value, boolean forceCreate, CoreAbstractSession session) { |
| NodeList list = addElements(fragment, xmlField, parent, value, forceCreate, null, noDocPresPolicy, session); |
| if (list.getLength() > 0) { |
| return list.item(0); |
| } |
| return null; |
| } |
| |
| /** |
| * Add a new <code>element</code> to the <code>parent</code> element. If an element with |
| * this name already exists, return it (unless <code>forceCreate</code> is <code>true</code>). |
| * |
| * @param fragment Name of element to create |
| * @param parent Parent element |
| * @param value Value for the new node |
| * @param forceCreate If true, create a new element even if one with the same name currently exists |
| |
| * @return The <code>NodeList</code> that was created/found |
| */ |
| private NodeList addElements(XPathFragment fragment, Field xmlField, Node parent, Object value, boolean forceCreate, Element sibling, DocumentPreservationPolicy docPresPolicy, CoreAbstractSession session) { |
| if (!forceCreate) { |
| NodeList nodes = unmarshalXPathEngine.selectElementNodes(parent, fragment, getNamespaceResolverForField(xmlField)); |
| if (nodes.getLength() > 0) { |
| return nodes; |
| } |
| } |
| |
| XMLNodeList elementsToReturn = new XMLNodeList(); |
| |
| if (value == this) { |
| String namespace = resolveNamespacePrefix(fragment, getNamespaceResolverForField(xmlField)); |
| Element newElement = parent.getOwnerDocument().createElementNS(namespace, fragment.getShortName()); |
| XPathPredicate predicate = fragment.getPredicate(); |
| if(predicate != null) { |
| XPathFragment predicateFragment = predicate.getXPathFragment(); |
| if(predicateFragment.isAttribute()) { |
| if(predicateFragment.getNamespaceURI() == null || predicateFragment.getNamespaceURI().length() == 0) { |
| newElement.setAttribute(predicateFragment.getLocalName(), fragment.getPredicate().getValue()); |
| } else { |
| String name = predicateFragment.getLocalName(); |
| if(predicateFragment.getPrefix() != null && predicateFragment.getPrefix().length() != 0) { |
| name = predicateFragment.getPrefix() + Constants.COLON + name; |
| } |
| newElement.setAttributeNS(predicateFragment.getNamespaceURI(), name, fragment.getPredicate().getValue()); |
| } |
| } |
| } |
| elementsToReturn.add(newElement); |
| docPresPolicy.getNodeOrderingPolicy().appendNode(parent, newElement, sibling); |
| |
| } else if (value == null) { |
| elementsToReturn.add(parent); |
| } else { |
| // Value may be a direct value, node, or list of values. |
| if (value instanceof List) { |
| List values = (List)value; |
| for (int index = 0; index < values.size(); index++) { |
| Element newElement = null; |
| |
| if (values.get(index) != XMLRecord.NIL) { |
| newElement = (Element) createElement(parent, fragment, xmlField, values.get(index), session); |
| } else { |
| newElement = (Element) createElement(parent, fragment, xmlField, Constants.EMPTY_STRING, session); |
| addXsiNilToElement(newElement, xmlField); |
| } |
| XPathPredicate predicate = fragment.getPredicate(); |
| if(predicate != null) { |
| XPathFragment predicateFragment = predicate.getXPathFragment(); |
| if(predicateFragment.isAttribute()) { |
| if(predicateFragment.getNamespaceURI() == null || predicateFragment.getNamespaceURI().length() == 0) { |
| newElement.setAttribute(predicateFragment.getLocalName(), fragment.getPredicate().getValue()); |
| } else { |
| String name = predicateFragment.getLocalName(); |
| if(predicateFragment.getPrefix() != null && predicateFragment.getPrefix().length() != 0) { |
| name = predicateFragment.getPrefix() + Constants.COLON + name; |
| } |
| newElement.setAttributeNS(predicateFragment.getNamespaceURI(), name, fragment.getPredicate().getValue()); |
| } |
| } |
| } |
| docPresPolicy.getNodeOrderingPolicy().appendNode(parent, newElement, sibling); |
| elementsToReturn.add(newElement); |
| sibling = newElement; |
| } |
| } else { |
| Element newElement = null; |
| if (value != XMLRecord.NIL) { |
| newElement = (Element)createElement(parent, fragment, xmlField, value, session); |
| } else { |
| newElement = (Element) createElement(parent, fragment, xmlField, Constants.EMPTY_STRING, session); |
| addXsiNilToElement(newElement, xmlField); |
| } |
| XPathPredicate predicate = fragment.getPredicate(); |
| if(predicate != null) { |
| XPathFragment predicateFragment = predicate.getXPathFragment(); |
| if(predicateFragment.isAttribute()) { |
| if(predicateFragment.getNamespaceURI() == null || predicateFragment.getNamespaceURI().length() == 0) { |
| newElement.setAttribute(predicateFragment.getLocalName(), fragment.getPredicate().getValue()); |
| } else { |
| String name = predicateFragment.getLocalName(); |
| if(predicateFragment.getPrefix() != null && predicateFragment.getPrefix().length() != 0) { |
| name = predicateFragment.getPrefix() + Constants.COLON + name; |
| } |
| newElement.setAttributeNS(predicateFragment.getNamespaceURI(), name, fragment.getPredicate().getValue()); |
| } |
| } |
| } |
| |
| docPresPolicy.getNodeOrderingPolicy().appendNode(parent, newElement, sibling); |
| elementsToReturn.add(newElement); |
| } |
| } |
| return elementsToReturn; |
| } |
| |
| /** |
| * Creates a new Element and appends a value to an element. |
| * |
| * @param parent Element which will own the newly created element |
| * @param fragment tag name for the new element |
| * @param value Object to add |
| */ |
| private Node createElement(Node parent, XPathFragment fragment, Field xmlField, Object value, CoreAbstractSession session) { |
| if (value == null) { |
| return parent; |
| } |
| if (value instanceof Node) { |
| return createElement(parent, fragment, getNamespaceResolverForField(xmlField), (Node)value); |
| } |
| Element element = null; |
| if (parent.getOwnerDocument() == null) { |
| element = ((Document)parent).getDocumentElement(); |
| } else { |
| String namespace = resolveNamespacePrefix(fragment, getNamespaceResolverForField(xmlField)); |
| NamespaceResolver domResolver = new NamespaceResolver(); |
| domResolver.setDOM(parent); |
| String existingPrefix = domResolver.resolveNamespaceURI(namespace); |
| String elementName = fragment.getShortName(); |
| if(existingPrefix != null) { |
| if(existingPrefix.length() > 0) { |
| elementName = existingPrefix + Constants.COLON + fragment.getLocalName(); |
| } else { |
| elementName = fragment.getLocalName(); |
| } |
| } |
| element = parent.getOwnerDocument().createElementNS(namespace, elementName); |
| if (fragment.isGeneratedPrefix() && existingPrefix == null) { |
| element.setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + fragment.getPrefix(), fragment.getNamespaceURI()); |
| } |
| XPathPredicate predicate = fragment.getPredicate(); |
| if(predicate != null) { |
| XPathFragment predicateFragment = predicate.getXPathFragment(); |
| if(predicateFragment.isAttribute()) { |
| element.setAttributeNS(predicateFragment.getNamespaceURI(), predicateFragment.getLocalName(), fragment.getPredicate().getValue()); |
| } |
| } |
| } |
| |
| XPathFragment nextFragment = fragment.getNextFragment(); |
| if ((nextFragment != null) && nextFragment.isAttribute()) { |
| addAttribute(nextFragment, xmlField, element, value, session); |
| } else if (value instanceof String && ((String)value).length() > 0) { |
| addText(xmlField, element, (String)value); |
| } else if (value == XMLRecord.NIL) { |
| addXsiNilToElement(element, xmlField); |
| } |
| return element; |
| } |
| |
| public Element createUnownedElement(Node parent, Field xmlField) { |
| XPathFragment lastFragment = xmlField.getXPathFragment(); |
| while (lastFragment.getNextFragment() != null) { |
| lastFragment = lastFragment.getNextFragment(); |
| } |
| String nodeName = lastFragment.getShortName(); |
| String namespace = resolveNamespacePrefix(lastFragment, getNamespaceResolverForField(xmlField)); |
| |
| NamespaceResolver domResolver = new NamespaceResolver(); |
| domResolver.setDOM(parent); |
| String existingPrefix = domResolver.resolveNamespaceURI(namespace); |
| String elementName = nodeName; |
| if(existingPrefix != null) { |
| if(existingPrefix.length() > 0) { |
| elementName = existingPrefix + Constants.COLON + lastFragment.getLocalName(); |
| } else { |
| elementName = lastFragment.getLocalName(); |
| } |
| } |
| |
| Element elem = parent.getOwnerDocument().createElementNS(namespace, elementName); |
| if (lastFragment.isGeneratedPrefix() && existingPrefix == null) { |
| elem.setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + lastFragment.getPrefix(), lastFragment.getNamespaceURI()); |
| } |
| |
| return elem; |
| } |
| |
| /** |
| * Adds a type attribute on an element, the value of the attribute is determined |
| * by performing a lookup in the SimpleTypeTranslator to find the Schema type |
| * for the value. |
| * |
| * @param elements NodeList which will have a type attribute added to them |
| * @param value Object to base the lookup on |
| * @param schemaInstancePrefix the prefix representing the schema instance namespace |
| */ |
| private void addTypeAttributes(NodeList elements, Field field, Object value, String schemaInstancePrefix, CoreAbstractSession session) { |
| NamespaceResolver namespaceResolver = getNamespaceResolverForField(field); |
| if (!field.isTypedTextField()) { |
| return; |
| } |
| |
| List values; |
| if (value instanceof List) { |
| values = (List)value; |
| } else { |
| values = new ArrayList(); |
| values.add(value); |
| } |
| |
| int size = elements.getLength(); |
| int valuesSize = values.size(); |
| |
| if (size != valuesSize) { |
| return; |
| } |
| |
| Node next = null; |
| for (int i = 0; i < size; i++) { |
| next = elements.item(i); |
| if (next.getNodeType() == Node.ELEMENT_NODE) { |
| Class<? extends Object> valueClass = values.get(i).getClass(); |
| if(valueClass != CoreClassConstants.STRING){ |
| ConversionManager conversionManager = (ConversionManager) session.getDatasourcePlatform().getConversionManager(); |
| QName qname = field.getXMLType(valueClass, conversionManager); |
| if (qname != null) { |
| if (null == schemaInstancePrefix) { |
| schemaInstancePrefix = namespaceResolver.generatePrefix(Constants.SCHEMA_INSTANCE_PREFIX); |
| ((Element)next).setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + schemaInstancePrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); |
| } |
| |
| String type; |
| String prefix = this.resolveNamespacePrefixForURI(qname.getNamespaceURI(), namespaceResolver); |
| if (prefix == null || prefix.length() == 0) { |
| if(qname.getNamespaceURI().equals(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI)){ |
| prefix = namespaceResolver.generatePrefix(Constants.SCHEMA_PREFIX); |
| }else{ |
| prefix = namespaceResolver.generatePrefix(); |
| } |
| ((Element)next).setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + prefix, qname.getNamespaceURI()); |
| } |
| type = prefix + Constants.COLON + qname.getLocalPart(); |
| ((Element)next).setAttributeNS(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, schemaInstancePrefix + Constants.COLON + Constants.SCHEMA_TYPE_ATTRIBUTE, type); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Creates a new Element and appends a value to an element. |
| * |
| * @param parent Element which will own the newly created element |
| * @param fragment tag name for the new element |
| * @param value Node to add |
| * |
| */ |
| private Node createElement(Node parent, XPathFragment fragment, NamespaceResolver namespaceResolver, Node value) { |
| // The case of the parent being the document (element is the root) needs to be handled. |
| // Document have no owner document, but are the document. |
| Document document = parent.getOwnerDocument(); |
| if ((document == null) && (parent.getNodeType() == Node.DOCUMENT_NODE)) { |
| document = (Document)parent; |
| } |
| |
| String nodeUri = value.getNamespaceURI(); |
| String nodeName = value.getLocalName(); |
| |
| //String fragUri = resolveNamespacePrefix(fragment, namespaceResolver); |
| String fragUri = fragment.getNamespaceURI(); |
| String fragName = fragment.getLocalName(); |
| |
| if ((nodeName != null) && nodeName.equals(fragName) && (((nodeUri != null) && nodeUri.equals(fragUri)) || ((nodeUri == null) && (fragUri == null)))) { |
| if (document != value.getOwnerDocument()) { |
| return document.importNode(value, true); |
| } |
| return value; |
| } else { |
| // Need to reset the node name. |
| String namespace = resolveNamespacePrefix(fragment, namespaceResolver); |
| Element clone = document.createElementNS(namespace, fragName); |
| NamedNodeMap attributes = value.getAttributes(); |
| int attributesLength = attributes.getLength(); |
| |
| for (int index = 0; index < attributesLength; index++) { |
| Node attribute = document.importNode(attributes.item(index), true); |
| clone.setAttributeNode((Attr)attribute); |
| } |
| |
| NodeList elements = value.getChildNodes(); |
| int elementsLength = elements.getLength(); |
| for (int index = 0; index < elementsLength; index++) { |
| Node attribute = document.importNode(elements.item(index), true); |
| clone.appendChild(attribute); |
| } |
| return clone; |
| } |
| } |
| |
| /** |
| * Add a new attribute to an element. If the attribute already exists, return the element. |
| * |
| * @param attributeFragment Name of the attribute to add |
| * @param parent Element to create the attribute on |
| * @param value Value for the new attribute |
| * |
| * @return The <code>XMLElement</code> that the attribute was added to (same as the <code>parent</code> parameter). |
| */ |
| private Node addAttribute(XPathFragment attributeFragment, Field xmlField, Node parent, Object value, CoreAbstractSession session) { |
| Object valueToWrite = null; |
| |
| if (!(parent instanceof Element)) { |
| return parent; |
| } |
| Element parentElement = (Element)parent; |
| if (value instanceof Node) { |
| if (((Node)value).getNodeType() == Node.ATTRIBUTE_NODE) { |
| Attr attr = (Attr)value; |
| if (parent.getAttributes().getNamedItemNS(attr.getNamespaceURI(), attr.getLocalName()) == null) { |
| String pfx = null; |
| if (xmlField.getNamespaceResolver() != null) { |
| pfx = getNamespaceResolverForField(xmlField).resolveNamespaceURI(attr.getNamespaceURI()); |
| } |
| if (pfx != null) { |
| // If the namespace resolver has a prefix for the node's URI, use it |
| parentElement.setAttributeNS(attr.getNamespaceURI(), pfx + Constants.COLON + attr.getLocalName(), attr.getNodeValue()); |
| } else { |
| // No entry for the node's URI in the resolver, so use the node's |
| // prefix/uri pair and define the URI locally |
| parentElement.setAttributeNS(attr.getNamespaceURI(), attr.getName(), attr.getNodeValue()); |
| } |
| } |
| return parent; |
| } |
| valueToWrite = value; |
| } else { |
| valueToWrite = getNonNodeValueToWrite(value, xmlField, session); |
| } |
| |
| String attributeName = attributeFragment.getLocalName(); |
| String attributeNamespace = resolveNamespacePrefix(attributeFragment, getNamespaceResolverForField(xmlField)); |
| if ((valueToWrite != null) && (parent.getAttributes().getNamedItemNS(attributeNamespace, attributeName) == null)) { |
| if (valueToWrite == this) { |
| parentElement.setAttributeNS(attributeNamespace, attributeFragment.getShortName(), Constants.EMPTY_STRING); |
| } else if (valueToWrite instanceof String) { |
| parentElement.setAttributeNS(attributeNamespace, attributeFragment.getShortName(), (String)valueToWrite); |
| } |
| if (attributeFragment.isGeneratedPrefix()) { |
| parentElement.setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + attributeFragment.getPrefix(), attributeFragment.getNamespaceURI()); |
| } |
| } |
| return parent; |
| } |
| |
| // ========================================================================================== |
| |
| /** |
| * Remove a node. If <code>xpathString</code> points to an indexed element, the element will not be removed, |
| * but will instead be reinitialzed (to maintain the index of the collection). |
| * |
| * @param xmlField Field containing XPath query string |
| * @param element Root element at which to begin search |
| * |
| * @return <code>NodeList</code> containing the nodes that were removed. |
| * |
| * @exception XMLMarshalException Thrown if passed an invalid XPath string |
| */ |
| public NodeList remove(Field xmlField, Node element) throws XMLMarshalException { |
| return remove(xmlField, element, false); |
| } |
| |
| /** |
| * Remove a node. |
| * |
| * @param xmlField Field containing XPath query string |
| * @param element Root element at which to begin search |
| * @param forceRemove If <code>true</code>, then indexed elements will be truly deleted, otherwise they will be reinitialized |
| * |
| * @return <code>NodeList</code> containing the nodes that were removed. |
| * |
| * @exception XMLMarshalException Thrown if passed an invalid XPath string |
| */ |
| public NodeList remove(Field xmlField, Node element, boolean forceRemove) throws XMLMarshalException { |
| String xpathString = xmlField.getXPath(); |
| NodeList nodes = unmarshalXPathEngine.selectNodes(element, xmlField, getNamespaceResolverForField(xmlField)); |
| int numberOfNodes = nodes.getLength(); |
| |
| boolean shouldNullOutNode = containsIndex(xpathString) && !forceRemove; |
| |
| // Remove the element or attribute, for positional element null-out instead of remove. |
| for (int i = 0; i < numberOfNodes; i++) { |
| Node node = nodes.item(i); |
| if (node.getNodeType() == Node.ATTRIBUTE_NODE) { |
| ((Attr)node).getOwnerElement().removeAttribute(node.getNodeName()); |
| } else { |
| if (shouldNullOutNode) { |
| Node blankNode = node.getParentNode().getOwnerDocument().createElementNS(node.getNamespaceURI(), node.getNodeName()); |
| node.getParentNode().replaceChild(blankNode, node); |
| } else { |
| node.getParentNode().removeChild(node); |
| } |
| } |
| } |
| |
| return nodes; |
| } |
| |
| // ========================================================================================== |
| |
| /** |
| * Replace the value of the nodes matching <code>xpathString</code> with <code>value</code>. |
| * This method handles elements, indexed elements, and attributes. |
| * |
| * @param xmlField Field containing XPath query string |
| * @param parent Parent element |
| * @param value New value for the node |
| * |
| * @return <code>NodeList</code> containing the nodes that were replaced. |
| */ |
| public NodeList replaceValue(Field xmlField, Node parent, Object value, CoreAbstractSession session) throws XMLMarshalException { |
| NodeList nodes = unmarshalXPathEngine.selectNodes(parent, xmlField, getNamespaceResolverForField(xmlField), null, false, false); |
| int numberOfNodes = nodes.getLength(); |
| if(numberOfNodes == 0 && xmlField.getLastXPathFragment().nameIsText()) { |
| nodes = unmarshalXPathEngine.selectNodes(parent, xmlField, getNamespaceResolverForField(xmlField), null, true); |
| XMLNodeList textNodes = new XMLNodeList(); |
| for(int i = 0; i < nodes.getLength(); i++) { |
| Element nextNode = (Element)nodes.item(i); |
| Text text = nextNode.getOwnerDocument().createTextNode(""); |
| nextNode.appendChild(text); |
| textNodes.add(text); |
| } |
| numberOfNodes = textNodes.getLength(); |
| nodes = textNodes; |
| } |
| XMLNodeList createdElements = new XMLNodeList(); |
| for (int i = 0; i < numberOfNodes; i++) { |
| Node node = nodes.item(i); |
| |
| // Handle Attributes and Text |
| if (node.getNodeType() != Node.ELEMENT_NODE) { |
| if (((node.getNodeType() == Node.TEXT_NODE) || (node.getNodeType() == Node.CDATA_SECTION_NODE)) && (value == null)) { |
| //if parent has only text children, remove parent. If parent has non-text children, |
| //remove all text children. |
| Node parentNode = node.getParentNode(); |
| if(parentNode != null) { |
| Node grandParentNode = parentNode.getParentNode(); |
| NodeList childNodes = parentNode.getChildNodes(); |
| if(childNodes.getLength() == numberOfNodes) { |
| grandParentNode.removeChild(parentNode); |
| } else { |
| for(int x = 0; x < childNodes.getLength(); x++) { |
| Node next = childNodes.item(x); |
| if(next.getNodeType() == Node.TEXT_NODE || next.getNodeType() == Node.CDATA_SECTION_NODE) { |
| parentNode.removeChild(next); |
| } |
| } |
| } |
| } |
| } else { |
| if(value == null) { |
| ((Attr)node).getOwnerElement().removeAttributeNode((Attr)node); |
| } else { |
| if(value == XMLRecord.NIL && ((node.getNodeType() == Node.TEXT_NODE) || (node.getNodeType() == Node.CDATA_SECTION_NODE))) { |
| Element parentElement = (Element)node.getParentNode(); |
| addXsiNilToElement(parentElement, xmlField); |
| parentElement.removeChild(node); |
| } else { |
| String stringValue = session.getDatasourcePlatform().getConversionManager().convertObject(value, CoreClassConstants.STRING); |
| Element parentElement = (Element)node.getParentNode(); |
| if(parentElement == null && parent.getNodeType() == Node.ELEMENT_NODE) { |
| parentElement = (Element)parent; |
| } |
| if(stringValue.length() == 0 && ((node.getNodeType() == Node.TEXT_NODE) || (node.getNodeType() == Node.CDATA_SECTION_NODE)) && parentElement != null) { |
| parentElement.removeChild(node); |
| } else { |
| node.setNodeValue(stringValue); |
| if(((node.getNodeType() == Node.TEXT_NODE) || (node.getNodeType() == Node.CDATA_SECTION_NODE)) && parentElement != null) { |
| Attr nil = parentElement.getAttributeNodeNS(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_NIL_ATTRIBUTE); |
| if(nil != null) { |
| parentElement.removeAttributeNode(nil); |
| } |
| } |
| } |
| } |
| } |
| } |
| } else { |
| Element element = (Element)node; |
| Node parentNode = element.getParentNode(); |
| if (value == null) { |
| parentNode.removeChild(element); |
| } else { |
| String elementName = element.getTagName(); |
| |
| Element newElement = null; |
| |
| Object valueToWrite = getValueToWrite(value, xmlField, session); |
| XPathFragment childFrag = new XPathFragment(elementName); |
| childFrag.setNamespaceURI(element.getNamespaceURI()); |
| newElement = (Element)createElement(parentNode, childFrag, xmlField, valueToWrite, session); |
| |
| createdElements.add(newElement); |
| |
| |
| if (newElement != element) { |
| parentNode.replaceChild(newElement, element); |
| } |
| } |
| } |
| } |
| if (xmlField.isTypedTextField()) { |
| |
| addTypeAttributes(createdElements, xmlField, value, resolveNamespacePrefixForURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, getNamespaceResolverForField(xmlField)), session); |
| } |
| return nodes; |
| } |
| |
| public List<XMLEntry> replaceCollection(List<Field> xmlFields, List<XMLEntry> values, Node contextNode, DocumentPreservationPolicy docPresPolicy, Field lastUpdatedField, CoreAbstractSession session) { |
| List<XMLEntry> oldNodes = unmarshalXPathEngine.selectNodes(contextNode, xmlFields, getNamespaceResolverForField(xmlFields.get(0))); |
| if(oldNodes == null || oldNodes.size() == 0) { |
| return oldNodes; |
| } |
| |
| Iterator<XMLEntry> oldValues = oldNodes.iterator(); |
| //Remove all the old values, and then call create to add them back in. |
| while(oldValues.hasNext()) { |
| XMLEntry entry = oldValues.next(); |
| Node nextNode = (Node)entry.getValue(); |
| Node parent = nextNode.getParentNode(); |
| parent.removeChild(nextNode); |
| while(parent != contextNode) { |
| if(parent.getChildNodes().getLength() == 0) { |
| nextNode = parent; |
| parent = nextNode.getParentNode(); |
| parent.removeChild(nextNode); |
| } else { |
| break; |
| } |
| } |
| } |
| |
| create(xmlFields, contextNode, values, lastUpdatedField, xmlBinderPolicy, session); |
| |
| return oldNodes; |
| } |
| public NodeList replaceCollection(Field xmlField, Node parent, Collection values, CoreAbstractSession session) throws XMLMarshalException { |
| NodeList nodes = null; |
| if (xmlField != null) { |
| nodes = unmarshalXPathEngine.selectNodes(parent, xmlField, getNamespaceResolverForField(xmlField)); |
| } else { |
| nodes = parent.getChildNodes(); |
| } |
| if (nodes.getLength() == 0) { |
| return nodes; |
| } |
| Iterator collectionValues = values.iterator(); |
| int i = 0; |
| |
| int nodesLength = nodes.getLength(); |
| Vector newNodes = new Vector(); |
| |
| // Iterate over both collections until one runs out, creating a collection of correct nodes |
| // while removing the old ones. |
| boolean performedReplace = true; |
| Object value = null; |
| while ((i < nodesLength) && collectionValues.hasNext()) { |
| //Keep track of which nodes have been replaced |
| Node oldChild = nodes.item(i); |
| Element newChild = null; |
| if (performedReplace) { |
| value = collectionValues.next(); |
| } |
| Node parentNode = oldChild.getParentNode(); |
| |
| // Handle Attributes and Text |
| if (oldChild.getNodeType() != Node.ELEMENT_NODE) { |
| if (((oldChild.getNodeType() == Node.TEXT_NODE) || (oldChild.getNodeType() == Node.CDATA_SECTION_NODE)) && (value == null)) { |
| Node grandParentNode = parentNode.getParentNode(); |
| grandParentNode.removeChild(parentNode); |
| } else { |
| oldChild.setNodeValue(session.getDatasourcePlatform().getConversionManager().convertObject(value, CoreClassConstants.STRING)); |
| } |
| } else { |
| Element element = (Element)oldChild; |
| String elementName = element.getTagName(); |
| Object valueToWrite = getValueToWrite(value, xmlField, session); |
| XPathFragment childFragment = new XPathFragment(elementName); |
| childFragment.setNamespaceURI(element.getNamespaceURI()); |
| newChild = (Element)createElement(parentNode, childFragment, xmlField, valueToWrite, session); |
| if (!newNodes.contains(oldChild)) { |
| if (newChild != oldChild) { |
| parentNode.replaceChild(newChild, oldChild); |
| } |
| newNodes.addElement(newChild); |
| performedReplace = true; |
| } else { |
| performedReplace = false; |
| } |
| } |
| i++; |
| } |
| |
| // This means collection was ran out first. Remove left-overs. |
| while (i < nodesLength) { |
| Node toRemove = nodes.item(i); |
| Node removedParent = toRemove.getParentNode(); |
| if ((removedParent != null) && !newNodes.contains(toRemove)) { |
| //only remove it, if it's not already been added back in |
| removedParent.removeChild(toRemove); |
| } |
| i++; |
| } |
| |
| //Now add the nodes back in, in the correct order |
| //for (Iterator newNodesIter = newNodes.iterator(); newNodesIter.hasNext();) { |
| // Element newNode = (Element)newNodesIter.next(); |
| //this.create(xmlField, parent, newNode); |
| //} |
| if ((value != null) && !performedReplace) { |
| //If we didn't add in the last element we tried then add it now |
| if ((xmlField.getXPathFragment().getNextFragment() == null) || xmlField.getXPathFragment().getHasText()) { |
| //if there's no grouping element, ensure that new collection elements |
| //are added inline with the others |
| create(xmlField, parent, value, xmlField, xmlBinderPolicy, session); |
| } else { |
| create(xmlField, parent, value, session); |
| } |
| } |
| |
| // Now add in any others that are left in the iterator |
| while (collectionValues.hasNext()) { |
| value = collectionValues.next(); |
| //If there's a grouping element, then just do the normal create |
| if ((xmlField.getXPathFragment().getNextFragment() == null) || xmlField.getXPathFragment().getHasText()) { |
| //if there's no grouping element, ensure that new collection elements |
| //are added inline with the others |
| create(xmlField, parent, value, xmlField, xmlBinderPolicy, session); |
| } else { |
| create(xmlField, parent, value, session); |
| } |
| } |
| |
| return nodes; |
| } |
| |
| // ========================================================================================== |
| |
| /** |
| * Determine if <code>xpathString</code> contains an index (e.g. 'element[index]'). |
| * |
| * @param xpathString XPath expression to test |
| * |
| * @return <code>true</code> if <code>xpathString</code> contains an index, otherwise <code>false</code>. |
| */ |
| private boolean containsIndex(String xpathString) { |
| return (xpathString.lastIndexOf('[') != -1) && (xpathString.lastIndexOf(']') != -1); |
| } |
| |
| private String resolveNamespacePrefix(XPathFragment fragment, NamespaceResolver namespaceResolver) { |
| try { |
| if (fragment.getNamespaceURI() != null) { |
| return fragment.getNamespaceURI(); |
| } |
| if(fragment.getPrefix() == null && fragment.isAttribute()) { |
| return null; |
| } |
| return namespaceResolver.resolveNamespacePrefix(fragment.getPrefix()); |
| } catch (Exception e) { |
| return null; |
| } |
| } |
| |
| private String resolveNamespacePrefixForURI(String namespaceURI, NamespaceResolver namespaceResolver) { |
| if (null == namespaceResolver) { |
| return null; |
| } |
| return namespaceResolver.resolveNamespaceURI(namespaceURI); |
| } |
| |
| private Node addText(Field xmlField, Node element, String textValue) { |
| if (xmlField.isCDATA()) { |
| CDATASection cdata = element.getOwnerDocument().createCDATASection(textValue); |
| element.appendChild(cdata); |
| return cdata; |
| } else { |
| Text text = element.getOwnerDocument().createTextNode(textValue); |
| element.appendChild(text); |
| return text; |
| } |
| } |
| private String getStringForQName(QName qName, NamespaceResolver namespaceResolver){ |
| if(null == qName) { |
| return null; |
| } |
| |
| if(null == qName.getNamespaceURI()) { |
| return qName.getLocalPart(); |
| } else { |
| String namespaceURI = qName.getNamespaceURI(); |
| if(namespaceResolver == null){ |
| throw XMLMarshalException.namespaceResolverNotSpecified(namespaceURI); |
| } |
| String prefix = namespaceResolver.resolveNamespaceURI(namespaceURI); |
| if(null == prefix) { |
| return qName.getLocalPart(); |
| } else { |
| return prefix + Constants.COLON + qName.getLocalPart(); |
| } |
| } |
| |
| } |
| |
| private NamespaceResolver getNamespaceResolverForField(Field field){ |
| NamespaceResolver nr = (org.eclipse.persistence.oxm.NamespaceResolver) field.getNamespaceResolver(); |
| if(nr == null){ |
| field.setNamespaceResolver(new NamespaceResolver()); |
| } |
| return (org.eclipse.persistence.oxm.NamespaceResolver) field.getNamespaceResolver(); |
| } |
| |
| private void addXsiNilToElement(Element element, Field xmlField) { |
| NamespaceResolver nsr = new NamespaceResolver(); |
| nsr.setDOM(element); |
| |
| String schemaInstancePrefix = resolveNamespacePrefixForURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, nsr); |
| Node parentNode = element.getParentNode(); |
| while(schemaInstancePrefix == null && parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE){ |
| nsr.setDOM(element); |
| schemaInstancePrefix = resolveNamespacePrefixForURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, nsr); |
| parentNode = parentNode.getParentNode(); |
| } |
| if(schemaInstancePrefix == null && element.getOwnerDocument() != null){ |
| nsr.setDOM(element.getOwnerDocument().getDocumentElement()); |
| schemaInstancePrefix = resolveNamespacePrefixForURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, nsr); |
| } |
| |
| if(schemaInstancePrefix == null) { |
| //Not decalred in the doc |
| nsr = getNamespaceResolverForField(xmlField); |
| schemaInstancePrefix = nsr.resolveNamespaceURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); |
| if(schemaInstancePrefix == null) { |
| schemaInstancePrefix = nsr.generatePrefix(Constants.SCHEMA_INSTANCE_PREFIX); |
| } |
| element.setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + schemaInstancePrefix, javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); |
| } |
| element.setAttributeNS(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_INSTANCE_PREFIX + Constants.COLON + Constants.SCHEMA_NIL_ATTRIBUTE, Constants.BOOLEAN_STRING_TRUE); |
| |
| } |
| } |