/**
* <copyright>
*
* Copyright (c) 2002-2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
*
* </copyright>
*
* $Id: XMLHelperImpl.java,v 1.57 2009/04/20 22:27:14 davidms Exp $
*/
package org.eclipse.emf.ecore.xmi.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import javax.xml.namespace.QName;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.BasicEMap;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.InternalEList;
import org.eclipse.emf.ecore.xmi.DanglingHREFException;
import org.eclipse.emf.ecore.xmi.IllegalValueException;
import org.eclipse.emf.ecore.xmi.NameInfo;
import org.eclipse.emf.ecore.xmi.XMIException;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xml.type.SimpleAnyType;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
/**
* This class handles the package to use when there is no XML
* namespace in an XML file.
*/
public class XMLHelperImpl implements XMLHelper
{
protected static final Integer INTEGER_DATATYPE_IS_MANY = DATATYPE_IS_MANY;
protected static final Integer INTEGER_DATATYPE_SINGLE = DATATYPE_SINGLE;
protected static final Integer INTEGER_IS_MANY_ADD = IS_MANY_ADD;
protected static final Integer INTEGER_IS_MANY_MOVE = IS_MANY_MOVE;
protected static final Integer INTEGER_OTHER = OTHER;
protected EPackage noNamespacePackage;
protected XMLResource.XMLMap xmlMap;
protected ExtendedMetaData extendedMetaData;
protected boolean laxFeatureProcessing;
protected EPackage.Registry packageRegistry;
protected XMLResource resource;
protected URI resourceURI;
protected boolean deresolve;
protected Map<EPackage, String> packages;
protected Map<EStructuralFeature, Integer> featuresToKinds;
protected String processDanglingHREF;
protected DanglingHREFException danglingHREFException;
protected EMap<String, String> prefixesToURIs;
protected Map<String, List<String>> urisToPrefixes;
protected Map<String, String> anyPrefixesToURIs;
protected NamespaceSupport namespaceSupport;
protected EClass anySimpleType;
// true if seen xmlns="" declaration
protected boolean seenEmptyStringMapping;
protected EPackage xmlSchemaTypePackage = XMLTypePackage.eINSTANCE;
protected List<String> allPrefixToURI;
protected boolean checkForDuplicates;
protected boolean mustHavePrefix;
protected XMLResource.URIHandler uriHandler;
protected List<? extends EObject> roots;
protected String [] fragmentPrefixes;
private EPackage previousPackage;
private String previousNS;
public static String saveString(Map<?, ?> options, List<? extends EObject> contents, String encoding, XMLHelper helper) throws Exception
{
if (helper == null)
{
helper = new XMIHelperImpl();
}
if (!options.containsKey(XMLResource.OPTION_DECLARE_XML))
{
Map<Object, Object> modifiedOptions = new HashMap<Object, Object>(options);
modifiedOptions.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE);
options = modifiedOptions;
}
XMLSaveImpl save = new XMISaveImpl(options, helper, encoding);
if (Boolean.TRUE.equals(options.get(XMLResource.OPTION_DEFER_IDREF_RESOLUTION)))
{
((XMLHelperImpl)helper).checkForDuplicates = true;
}
((XMLHelperImpl)helper).processDanglingHREF = (String)options.get(XMLResource.OPTION_PROCESS_DANGLING_HREF);
save.traverse(contents);
if (save.useCache)
{
if (save.doc != null)
{
ConfigurationCache.INSTANCE.releasePrinter(save.doc);
}
if (save.escape != null)
{
ConfigurationCache.INSTANCE.releaseEscape(save.escape);
}
}
char[] chars = save.toChar();
return new String(chars);
}
public XMLHelperImpl()
{
super();
packages = new HashMap<EPackage, String>();
featuresToKinds = new HashMap<EStructuralFeature, Integer>();
prefixesToURIs =
new BasicEMap<String, String>()
{
private static final long serialVersionUID = 1L;
protected List<String> getPrefixes(String uri)
{
List<String> result = urisToPrefixes.get(uri);
if (result == null)
{
urisToPrefixes.put(uri, result = new ArrayList<String>());
}
return result;
}
@Override
protected void didAdd(Entry<String, String> entry)
{
getPrefixes(entry.getValue()).add(entry.getKey());
}
@Override
protected void didClear(BasicEList<Entry<String, String>>[] oldEntryData)
{
urisToPrefixes.clear();
}
@Override
protected void didModify(Entry<String, String> entry, String oldValue)
{
String key = entry.getKey();
getPrefixes(oldValue).remove(key);
getPrefixes(entry.getValue()).add(key);
}
@Override
protected void didRemove(Entry<String, String> entry)
{
getPrefixes(entry.getValue()).add(entry.getKey());
}
};
urisToPrefixes = new HashMap<String, List<String>>();
anyPrefixesToURIs = new HashMap<String, String>();
allPrefixToURI = new ArrayList<String>();
namespaceSupport = new NamespaceSupport();
}
public XMLHelperImpl(XMLResource resource)
{
this();
setResource(resource);
}
public void setOptions(Map<?, ?> options)
{
laxFeatureProcessing = Boolean.TRUE.equals(options.get(XMLResource.OPTION_LAX_FEATURE_PROCESSING));
uriHandler = (XMLResource.URIHandler)options.get(XMLResource.OPTION_URI_HANDLER);
if (uriHandler != null)
{
uriHandler.setBaseURI(resourceURI);
}
@SuppressWarnings("unchecked")
List<? extends EObject> roots = (List<? extends EObject>)options.get(XMLResource.OPTION_ROOT_OBJECTS);
if (roots != null)
{
this.roots = roots;
fragmentPrefixes = new String[roots.size()];
int count = 0;
for (EObject root : roots)
{
InternalEObject internalEObject = (InternalEObject)root;
List<String> uriFragmentPath = new ArrayList<String>();
for (InternalEObject container = internalEObject.eInternalContainer(); container != null; container = internalEObject.eInternalContainer())
{
uriFragmentPath.add(container.eURIFragmentSegment(internalEObject.eContainingFeature(), internalEObject));
internalEObject = container;
Resource resource = container.eDirectResource();
if (resource != null)
{
int index = resource.getContents().indexOf(container);
uriFragmentPath.add(index != 0 ? Integer.toString(index) : "");
break;
}
}
StringBuilder result = new StringBuilder("/");
for (int i = uriFragmentPath.size() - 1; i >= 1; --i)
{
result.append(uriFragmentPath.get(i));
result.append('/');
}
fragmentPrefixes[count++] = result.toString();
}
}
}
public void setNoNamespacePackage(EPackage pkg)
{
noNamespacePackage = pkg;
}
public EPackage getNoNamespacePackage()
{
return
noNamespacePackage != null ?
noNamespacePackage :
extendedMetaData != null ?
extendedMetaData.getPackage(null) :
null;
}
public void setXMLMap(XMLResource.XMLMap map)
{
xmlMap = map;
if (map != null && map.getNoNamespacePackage() != null)
{
setNoNamespacePackage(map.getNoNamespacePackage());
}
}
public XMLResource.XMLMap getXMLMap()
{
return xmlMap;
}
public void setExtendedMetaData(ExtendedMetaData extendedMetaData)
{
this.extendedMetaData = extendedMetaData;
if (extendedMetaData != null && extendedMetaData.getPackage(null) != null)
{
setNoNamespacePackage(extendedMetaData.getPackage(null));
}
}
public ExtendedMetaData getExtendedMetaData()
{
return extendedMetaData;
}
public XMLResource getResource()
{
return resource;
}
public void setResource(XMLResource resource)
{
this.resource = resource;
if (resource == null)
{
resourceURI = null;
deresolve = false;
packageRegistry = EPackage.Registry.INSTANCE;
}
else
{
resourceURI = resource.getURI();
deresolve = resourceURI != null && !resourceURI.isRelative() && resourceURI.isHierarchical();
packageRegistry = resource.getResourceSet() == null ? EPackage.Registry.INSTANCE : resource.getResourceSet().getPackageRegistry();
}
}
public Object getValue(EObject obj, EStructuralFeature f)
{
return obj.eGet(f, false);
}
public String getQName(EClass c)
{
String name = getName(c);
if (xmlMap != null)
{
XMLResource.XMLInfo clsInfo = xmlMap.getInfo(c);
if (clsInfo != null)
{
String targetNamespace = clsInfo.getTargetNamespace();
return getQName(targetNamespace, name);
}
}
return getQName(c.getEPackage(), name);
}
public void populateNameInfo(NameInfo nameInfo, EClass c)
{
String name = getName(c);
nameInfo.setLocalPart(name);
if (xmlMap != null)
{
XMLResource.XMLInfo clsInfo = xmlMap.getInfo(c);
if (clsInfo != null)
{
String targetNamespace = clsInfo.getTargetNamespace();
nameInfo.setNamespaceURI(targetNamespace);
nameInfo.setQualifiedName(getQName(targetNamespace, name));
return;
}
}
getQName(nameInfo, c.getEPackage(), name);
}
public String getQName(EDataType c)
{
String name = getName(c);
if (xmlMap != null)
{
XMLResource.XMLInfo clsInfo = xmlMap.getInfo(c);
if (clsInfo != null)
{
String targetNamespace = clsInfo.getTargetNamespace();
return getQName(targetNamespace, name);
}
}
return getQName(c.getEPackage(), name);
}
public void populateNameInfo(NameInfo nameInfo, EDataType eDataType)
{
String name = getName(eDataType);
nameInfo.setLocalPart(name);
if (xmlMap != null)
{
XMLResource.XMLInfo clsInfo = xmlMap.getInfo(eDataType);
if (clsInfo != null)
{
String targetNamespace = clsInfo.getTargetNamespace();
nameInfo.setNamespaceURI(targetNamespace);
nameInfo.setQualifiedName(getQName(targetNamespace, name));
return;
}
}
getQName(nameInfo, eDataType.getEPackage(), name);
}
public String getQName(EStructuralFeature feature)
{
if (extendedMetaData != null)
{
String namespace = extendedMetaData.getNamespace(feature);
String name = extendedMetaData.getName(feature);
String result = name;
// We need to be careful that we don't end up requiring the no namespace package
// just because the feature is unqualified.
//
if (namespace != null)
{
// There really must be a package.
//
EPackage ePackage;
if (namespace.equals(previousNS))
{
ePackage = previousPackage;
}
else
{
ePackage = extendedMetaData.getPackage(namespace);
if (ePackage == null)
{
ePackage = extendedMetaData.demandPackage(namespace);
}
previousPackage = ePackage;
previousNS = namespace;
}
result = getQName(ePackage, name);
// We must have a qualifier for an attribute that needs qualified.
//
if (result.length() == name.length() && extendedMetaData.getFeatureKind(feature) == ExtendedMetaData.ATTRIBUTE_FEATURE)
{
result = getQName(ePackage, name, true);
}
}
return result;
}
String name = getName(feature);
if (xmlMap != null)
{
XMLResource.XMLInfo info = xmlMap.getInfo(feature);
if (info != null)
{
return getQName(info.getTargetNamespace(), name);
}
}
return name;
}
public void populateNameInfo(NameInfo nameInfo, EStructuralFeature feature)
{
if (extendedMetaData != null)
{
String namespace = extendedMetaData.getNamespace(feature);
String name = extendedMetaData.getName(feature);
nameInfo.setNamespaceURI(namespace);
nameInfo.setLocalPart(name);
nameInfo.setQualifiedName(name);
// We need to be careful that we don't end up requiring the no namespace package
// just because the feature is unqualified.
//
if (namespace != null)
{
// There really must be a package.
//
EPackage ePackage = extendedMetaData.getPackage(namespace);
if (ePackage == null)
{
ePackage = extendedMetaData.demandPackage(namespace);
}
String result = getQName(nameInfo, ePackage, name);
// We must have a qualifier for an attribute that needs qualified.
//
if (result.length() == name.length() && extendedMetaData.getFeatureKind(feature) == ExtendedMetaData.ATTRIBUTE_FEATURE)
{
getQName(nameInfo, ePackage, name, true);
}
}
}
else
{
String name = getName(feature);
nameInfo.setNamespaceURI(null);
nameInfo.setLocalPart(name);
if (xmlMap != null)
{
XMLResource.XMLInfo info = xmlMap.getInfo(feature);
if (info != null)
{
String targetNamespace = info.getTargetNamespace();
nameInfo.setNamespaceURI(targetNamespace);
nameInfo.setQualifiedName(getQName(targetNamespace, name));
}
}
nameInfo.setQualifiedName(name);
}
}
protected String getQName(NameInfo nameInfo, EPackage ePackage, String name)
{
String qname = getQName(nameInfo, ePackage, name, mustHavePrefix);
nameInfo.setQualifiedName(qname);
return qname;
}
protected String getQName(NameInfo nameInfo, EPackage ePackage, String name, boolean mustHavePrefix)
{
String nsPrefix = getPrefix(ePackage, mustHavePrefix);
nameInfo.setNamespaceURI(getNamespaceURI(nsPrefix));
if ("".equals(nsPrefix))
{
return name;
}
else if (name.length() == 0)
{
return nsPrefix;
}
else
{
return nsPrefix + ":" + name;
}
}
protected String getQName(EPackage ePackage, String name)
{
return getQName(ePackage, name, mustHavePrefix);
}
protected String getQName(EPackage ePackage, String name, boolean mustHavePrefix)
{
String nsPrefix = getPrefix(ePackage, mustHavePrefix);
if ("".equals(nsPrefix))
{
return name;
}
else if (name.length() == 0)
{
return nsPrefix;
}
else
{
return nsPrefix + ":" + name;
}
}
public String getPrefix(EPackage ePackage)
{
return getPrefix(ePackage, mustHavePrefix);
}
public String getNamespaceURI(String prefix)
{
String namespaceURI = namespaceSupport.getURI(prefix);
if (namespaceURI == null)
{
namespaceURI = prefixesToURIs.get(prefix);
}
return namespaceURI;
}
protected String getPrefix(EPackage ePackage, boolean mustHavePrefix)
{
String nsPrefix = packages.get(ePackage);
if (nsPrefix == null || mustHavePrefix && nsPrefix.length() == 0)
{
String nsURI =
xmlSchemaTypePackage == ePackage ?
XMLResource.XML_SCHEMA_URI :
extendedMetaData == null ?
ePackage.getNsURI() :
extendedMetaData.getNamespace(ePackage);
boolean found = false;
List<String> prefixes = urisToPrefixes.get(nsURI);
if (prefixes != null)
{
for (String prefix : prefixes)
{
nsPrefix = prefix;
if (!mustHavePrefix || nsPrefix.length() > 0)
{
found = true;
break;
}
}
}
if (!found)
{
// for any content prefix to URI mapping could be in namespace context
nsPrefix = namespaceSupport.getPrefix(nsURI);
if (nsPrefix != null)
{
return nsPrefix;
}
if (nsURI != null)
{
nsPrefix = xmlSchemaTypePackage == ePackage ? "xsd" : ePackage.getNsPrefix();
}
if (nsPrefix == null)
{
nsPrefix = mustHavePrefix ? "_" : "";
}
if (prefixesToURIs.containsKey(nsPrefix))
{
String currentValue = prefixesToURIs.get(nsPrefix);
if (currentValue == null ? nsURI != null : !currentValue.equals(nsURI))
{
int index = 1;
while (prefixesToURIs.containsKey(nsPrefix + "_" + index))
{
++index;
}
nsPrefix += "_" + index;
}
}
prefixesToURIs.put(nsPrefix, nsURI);
}
if (!packages.containsKey(ePackage))
{
packages.put(ePackage, nsPrefix);
}
}
return nsPrefix;
}
public List<String> getPrefixes(EPackage ePackage)
{
List<String> result = new UniqueEList<String>();
result.add(getPrefix(ePackage));
String namespace = extendedMetaData == null ? ePackage.getNsURI() : extendedMetaData.getNamespace(ePackage);
List<String> prefixes = urisToPrefixes.get(namespace);
if (prefixes != null)
{
result.addAll(prefixes);
}
return result;
}
protected String getQName(String uri, String name)
{
if (uri == null)
{
EPackage theNoNamespacePackage = getNoNamespacePackage();
if (theNoNamespacePackage != null)
{
packages.put(theNoNamespacePackage, "");
}
return name;
}
EPackage ePackage =
extendedMetaData == null ?
EPackage.Registry.INSTANCE.getEPackage(uri) :
extendedMetaData.getPackage(uri);
if (ePackage == null)
{
if (extendedMetaData != null)
{
return getQName(extendedMetaData.demandPackage(uri), name);
}
else
{
// EATM this would be wrong.
return name;
}
}
else
{
return getQName(ePackage, name);
}
}
public String getName(ENamedElement obj)
{
if (extendedMetaData != null)
{
return
obj instanceof EStructuralFeature ?
extendedMetaData.getName((EStructuralFeature)obj) :
extendedMetaData.getName((EClassifier)obj);
}
if (xmlMap != null)
{
XMLResource.XMLInfo info = xmlMap.getInfo(obj);
if (info != null)
{
String result = info.getName();
if (result != null)
{
return result;
}
}
}
return obj.getName();
}
public String getID(EObject obj)
{
return resource == null ? null : resource.getID(obj);
}
protected String getURIFragmentQuery(Resource containingResource, EObject object)
{
return null;
}
protected String getURIFragment(Resource containingResource, EObject object)
{
if (roots != null && containingResource == resource && !EcoreUtil.isAncestor(roots, object))
{
URI uriResult = handleDanglingHREF(object);
return uriResult == null || !uriResult.hasFragment() ? null : uriResult.fragment();
}
else
{
String result = containingResource.getURIFragment(object);
if (result.length() > 0 && result.charAt(0) != '/')
{
String query = getURIFragmentQuery(containingResource, object);
if (query != null)
{
result += "?" + query + "?";
}
}
else if ("/-1".equals(result))
{
if (object.eResource() != containingResource)
{
URI uriResult = handleDanglingHREF(object);
return uriResult == null || !uriResult.hasFragment() ? null : uriResult.fragment();
}
}
else if (fragmentPrefixes != null)
{
for (int i = 0; i < fragmentPrefixes.length; ++i)
{
String fragmentPrefix = fragmentPrefixes[i];
if (result.startsWith(fragmentPrefix))
{
result = "/" + (i == 0 ? "" : Integer.toString(i)) + result.substring(fragmentPrefix.length() - 1);
break;
}
}
}
return result;
}
}
public String getIDREF(EObject obj)
{
return resource == null ? null : getURIFragment(resource, obj);
}
protected URI handleDanglingHREF(EObject object)
{
if (!XMLResource.OPTION_PROCESS_DANGLING_HREF_DISCARD.equals(processDanglingHREF))
{
DanglingHREFException exception = new DanglingHREFException(
"The object '" + object + "' is not contained in a resource.",
resource == null || resource.getURI() == null ? "unknown" : resource.getURI().toString(), 0, 0);
if (danglingHREFException == null)
{
danglingHREFException = exception;
}
if (resource != null)
{
resource.getErrors().add(exception);
}
}
return null;
}
public String getHREF(EObject obj)
{
InternalEObject o = (InternalEObject) obj;
URI objectURI = o.eProxyURI();
if (objectURI == null)
{
Resource otherResource = obj.eResource();
if (otherResource == null)
{
if (resource != null && resource.getID(obj) != null)
{
objectURI = getHREF(resource, obj);
}
else
{
objectURI = handleDanglingHREF(obj);
if (objectURI == null)
{
return null;
}
}
}
else
{
objectURI = getHREF(otherResource, obj);
}
}
objectURI = deresolve(objectURI);
return objectURI.toString();
}
protected URI getHREF(Resource otherResource, EObject obj)
{
return otherResource.getURI().appendFragment(getURIFragment(otherResource, obj));
}
public URI deresolve(URI uri)
{
if (uriHandler != null)
{
uri = uriHandler.deresolve(uri);
}
else if (deresolve && !uri.isRelative())
{
URI deresolvedURI = uri.deresolve(resourceURI, true, true, false);
if (deresolvedURI.hasRelativePath())
{
uri = deresolvedURI;
}
}
return uri;
}
public int getFeatureKind(EStructuralFeature feature)
{
Integer kind = featuresToKinds.get(feature);
if (kind != null)
{
return kind;
}
else
{
computeFeatureKind(feature);
kind = featuresToKinds.get(feature);
if (kind != null)
{
return kind;
}
else
{
featuresToKinds.put(feature, INTEGER_OTHER);
return OTHER;
}
}
}
public EObject createObject(EFactory eFactory, EClassifier type)
{
EObject newObject = null;
if (eFactory != null)
{
if (extendedMetaData != null)
{
if (type == null)
{
return null;
}
else if (type instanceof EClass)
{
EClass eClass = (EClass)type;
if (!eClass.isAbstract())
{
newObject = eFactory.create((EClass)type);
}
}
else
{
SimpleAnyType result = (SimpleAnyType)EcoreUtil.create(anySimpleType);
result.setInstanceType((EDataType)type);
newObject = result;
}
}
else
{
if (type != null)
{
EClass eClass = (EClass)type;
if (!eClass.isAbstract())
{
newObject = eFactory.create((EClass)type);
}
}
}
}
return newObject;
}
public EClassifier getType(EFactory eFactory, String typeName)
{
if (eFactory != null)
{
EPackage ePackage = eFactory.getEPackage();
if (extendedMetaData != null)
{
return extendedMetaData.getType(ePackage, typeName);
}
else
{
EClass eClass = (EClass)ePackage.getEClassifier(typeName);
if (eClass == null && xmlMap != null)
{
return xmlMap.getClassifier(ePackage.getNsURI(), typeName);
}
return eClass;
}
}
return null;
}
/**
* @deprecated since 2.2
*/
@Deprecated
public EObject createObject(EFactory eFactory, String classXMIName)
{
return createObject(eFactory, getType(eFactory, classXMIName));
}
public EStructuralFeature getFeature(EClass eClass, String namespaceURI, String name)
{
EStructuralFeature feature = getFeatureWithoutMap(eClass, name);
if (feature == null)
{
if (xmlMap != null)
{
feature = xmlMap.getFeature(eClass, namespaceURI, name);
if (feature != null)
{
computeFeatureKind(feature);
}
}
else if (laxFeatureProcessing && extendedMetaData != null)
{
List<EStructuralFeature> structuralFeatures = eClass.getEAllStructuralFeatures();
for (int i = 0, size = structuralFeatures.size(); i < size; ++i)
{
EStructuralFeature eStructuralFeature = structuralFeatures.get(i);
if (name.equals(extendedMetaData.getName(eStructuralFeature))
&& (namespaceURI == null ? extendedMetaData.getNamespace(eStructuralFeature) == null : namespaceURI.equals(extendedMetaData.getNamespace(eStructuralFeature))))
{
return eStructuralFeature;
}
}
}
}
return feature;
}
public EStructuralFeature getFeature(EClass eClass, String namespaceURI, String name, boolean isElement)
{
if (extendedMetaData != null)
{
// Once we see a lookup of an element in the null namespace, we should behave as if there has been an explicit xmlns=""
//
if (isElement && namespaceURI == null)
{
seenEmptyStringMapping = true;
}
EStructuralFeature eStructuralFeature =
isElement ?
extendedMetaData.getElement(eClass, namespaceURI, name) :
extendedMetaData.getAttribute(eClass, namespaceURI == "" ? null : namespaceURI, name);
if (eStructuralFeature != null)
{
computeFeatureKind(eStructuralFeature);
}
else
{
eStructuralFeature = getFeature(eClass, namespaceURI, name);
// Only if the feature kind is unspecified should we return a match.
// Otherwise, we might return an attribute feature when an element is required,
// or vice versa. This also can be controlled by XMLResource.OPTION_LAX_FEATURE_PROCESSING.
//
if (!laxFeatureProcessing && eStructuralFeature != null &&
extendedMetaData.getFeatureKind(eStructuralFeature) != ExtendedMetaData.UNSPECIFIED_FEATURE)
{
eStructuralFeature = null;
}
}
return eStructuralFeature;
}
return getFeature(eClass, namespaceURI, name);
}
protected EStructuralFeature getFeatureWithoutMap(EClass eClass, String name)
{
EStructuralFeature feature = eClass.getEStructuralFeature(name);
if (feature != null)
computeFeatureKind(feature);
return feature;
}
protected void computeFeatureKind(EStructuralFeature feature)
{
EClassifier eClassifier = feature.getEType();
if (eClassifier instanceof EDataType)
{
if (feature.isMany())
{
featuresToKinds.put(feature, INTEGER_DATATYPE_IS_MANY);
}
else
{
featuresToKinds.put(feature, INTEGER_DATATYPE_SINGLE);
}
}
else
{
if (feature.isMany())
{
EReference reference = (EReference) feature;
EReference opposite = reference.getEOpposite();
if (opposite == null || opposite.isTransient() || !opposite.isMany())
featuresToKinds.put(feature, INTEGER_IS_MANY_ADD);
else
featuresToKinds.put(feature, INTEGER_IS_MANY_MOVE);
}
}
}
public String getJavaEncoding(String xmlEncoding)
{
return xmlEncoding;
}
public String getXMLEncoding(String javaEncoding)
{
return javaEncoding;
}
public EPackage[] packages()
{
Map<String, EPackage> map = new TreeMap<String, EPackage>();
// Sort and eliminate duplicates caused by having both a regular package and a demanded package for the same nsURI.
//
for (EPackage ePackage : packages.keySet())
{
String prefix= getPrefix(ePackage);
if (prefix == null)
{
prefix = "";
}
EPackage conflict = map.put(prefix, ePackage);
if (conflict != null && conflict.eResource() != null)
{
map.put(prefix, conflict);
}
}
EPackage[] result = new EPackage[map.size()];
map.values().toArray(result);
return result;
}
public void setValue(EObject object, EStructuralFeature feature, Object value, int position)
{
if (extendedMetaData != null)
{
EStructuralFeature targetFeature = extendedMetaData.getAffiliation(object.eClass(), feature);
if (targetFeature != null && targetFeature != feature)
{
EStructuralFeature group = extendedMetaData.getGroup(targetFeature);
if (group != null)
{
targetFeature = group;
}
if (targetFeature.getEType() == EcorePackage.Literals.EFEATURE_MAP_ENTRY)
{
FeatureMap featureMap = (FeatureMap)object.eGet(targetFeature);
EClassifier eClassifier = feature.getEType();
if (eClassifier instanceof EDataType)
{
EDataType eDataType = (EDataType) eClassifier;
EFactory eFactory = eDataType.getEPackage().getEFactoryInstance();
value = createFromString(eFactory, eDataType, (String)value);
}
featureMap.add(feature, value);
return;
}
else
{
// If we are substituting an EAttribute for an EReference...
//
EClassifier eType = feature.getEType();
if (eType instanceof EDataType && targetFeature instanceof EReference)
{
// Create an simple any type wrapper for the attribute value and use that with the EReference.
//
SimpleAnyType simpleAnyType = (SimpleAnyType)EcoreUtil.create(anySimpleType);
simpleAnyType.setInstanceType((EDataType)eType);
simpleAnyType.setRawValue((String)value);
value = simpleAnyType;
}
feature = targetFeature;
}
}
}
int kind = getFeatureKind(feature);
switch (kind)
{
case DATATYPE_SINGLE:
case DATATYPE_IS_MANY:
{
EClassifier eClassifier = feature.getEType();
EDataType eDataType = (EDataType) eClassifier;
EFactory eFactory = eDataType.getEPackage().getEFactoryInstance();
if (kind == DATATYPE_IS_MANY)
{
@SuppressWarnings("unchecked") InternalEList<Object> list = (InternalEList<Object>)object.eGet(feature);
if (position == -2)
{
for (StringTokenizer stringTokenizer = new StringTokenizer((String)value, " "); stringTokenizer.hasMoreTokens(); )
{
String token = stringTokenizer.nextToken();
list.addUnique(createFromString(eFactory, eDataType, token));
}
// Make sure that the list will appear to be set to be empty.
//
if (list.isEmpty())
{
list.clear();
}
}
else if (value == null)
{
list.addUnique(null);
}
else
{
list.addUnique(createFromString(eFactory, eDataType, (String)value));
}
}
else if (value == null)
{
object.eSet(feature, null);
}
else
{
object.eSet(feature, createFromString(eFactory, eDataType, (String) value));
}
break;
}
case IS_MANY_ADD:
case IS_MANY_MOVE:
{
@SuppressWarnings("unchecked") InternalEList<Object> list = (InternalEList<Object>)object.eGet(feature);
if (position == -1)
{
if (object == value)
{
list.add(value);
}
else
{
list.addUnique(value);
}
}
else if (position == -2)
{
list.clear();
}
else if (checkForDuplicates || object == value)
{
int index = list.basicIndexOf(value);
if (index == -1)
{
list.addUnique(position, value);
}
else
{
list.move(position, index);
}
}
else if (kind == IS_MANY_ADD)
{
list.addUnique(position, value);
}
else
{
list.move(position, value);
}
break;
}
default:
{
object.eSet(feature, value);
break;
}
}
}
public List<XMIException> setManyReference(ManyReference reference, String location)
{
EStructuralFeature feature = reference.getFeature();
int kind = getFeatureKind(feature);
EObject object = reference.getObject();
@SuppressWarnings("unchecked") InternalEList<Object> list = (InternalEList<Object>)object.eGet(feature);
List<XMIException> xmiExceptions = new BasicEList<XMIException>();
Object[] values = reference.getValues();
int[] positions = reference.getPositions();
if (kind == IS_MANY_ADD)
{
for (int i = 0, l = values.length; i < l; i++)
{
Object value = values[i];
if (value != null)
{
int position = positions[i];
try
{
if (checkForDuplicates || object == value)
{
int index = list.basicIndexOf(value);
if (index == -1)
{
list.addUnique(position, value);
}
else
{
list.move(position, index);
}
}
else
{
list.addUnique(position, value);
}
}
catch (RuntimeException e)
{
xmiExceptions.add(new IllegalValueException
(object,
feature,
value,
e,
location,
reference.getLineNumber(),
reference.getColumnNumber()
));
}
}
}
}
else
{
for (int i = 0, l = values.length; i < l; i++)
{
Object value = values[i];
if (value != null)
{
try
{
int sourcePosition = list.basicIndexOf(value);
if (sourcePosition != -1)
{
list.move(positions[i], sourcePosition);
}
else
{
list.addUnique(positions[i], value);
}
}
catch (RuntimeException e)
{
xmiExceptions.add(new IllegalValueException
(object,
feature,
value,
e,
location,
reference.getLineNumber(),
reference.getColumnNumber()
));
}
}
}
}
if (xmiExceptions.isEmpty())
{
return null;
}
else
{
return xmiExceptions;
}
}
public void setCheckForDuplicates(boolean checkForDuplicates)
{
this.checkForDuplicates = checkForDuplicates;
}
public void setProcessDanglingHREF(String value)
{
processDanglingHREF = value;
}
public DanglingHREFException getDanglingHREFException()
{
return danglingHREFException;
}
public URI resolve(URI relative, URI base)
{
return uriHandler == null ? relative.resolve(base) : uriHandler.resolve(relative);
}
public void pushContext()
{
namespaceSupport.pushContext();
}
public void popContext()
{
namespaceSupport.popContext();
}
public void popContext(Map<String, EFactory> prefixesToFactories)
{
namespaceSupport.popContext(prefixesToFactories);
}
public void addPrefix(String prefix, String uri)
{
if (!"xml".equals(prefix) && !"xmlns".equals(prefix))
{
uri = (uri.length() == 0) ? null : uri;
namespaceSupport.declarePrefix(prefix, uri);
allPrefixToURI.add(prefix);
allPrefixToURI.add(uri);
}
}
public String getPrefix (String namespaceURI)
{
return namespaceSupport.getPrefix(namespaceURI);
}
public Map<String, String> getAnyContentPrefixToURIMapping()
{
anyPrefixesToURIs.clear();
int count = namespaceSupport.getDeclaredPrefixCount();
int size = allPrefixToURI.size();
while (count-->0)
{
String uri = allPrefixToURI.remove(--size);
String prefix = allPrefixToURI.remove(--size);
anyPrefixesToURIs.put(prefix, uri);
}
return anyPrefixesToURIs;
}
public String getURI(String prefix)
{
return
"xml".equals(prefix) ?
"http://www.w3.org/XML/1998/namespace" :
"xmlns".equals(prefix) ?
ExtendedMetaData.XMLNS_URI :
namespaceSupport.getURI(prefix);
}
public EMap<String, String> getPrefixToNamespaceMap()
{
return prefixesToURIs;
}
public void recordPrefixToURIMapping()
{
for (int i = 0, size = allPrefixToURI.size(); i < size;)
{
String prefix = allPrefixToURI.get(i++);
String uri = allPrefixToURI.get(i++);
String originalURI = prefixesToURIs.get(prefix);
if (uri == null)
{
// xmlns="" declaration
// Example #1: <a><q-name>q</q-name><b xmlns="abc"/></a>
// Example #2: <a xmlns="abc"><b xmlns=""/><c xmlns="abc2"/></a>
// Example #3: <a xmlns:a="abc"><b xmlns:a="abc2"/></a>
seenEmptyStringMapping = true;
if (originalURI != null)
{
// since xmlns="" is default declaration, remove ""->empty_URI mapping
prefixesToURIs.removeKey(prefix);
addNSDeclaration(prefix, originalURI);
}
continue;
}
else if ((seenEmptyStringMapping && prefix.length() == 0))
{
// record default ns declaration as duplicate if seen QName (#1) or seen xmlns="" (#2)
addNSDeclaration(prefix, uri);
}
else if (originalURI != null)
{
if (!uri.equals(originalURI))
{
// record duplicate declaration for a given prefix (#3)
addNSDeclaration(prefix, uri);
}
}
else
{
// recording a first declaration for a given prefix
prefixesToURIs.put(prefix, uri);
}
}
}
public void setPrefixToNamespaceMap(EMap<String, String> prefixToNamespaceMap)
{
for (Map.Entry<String, String> entry : prefixToNamespaceMap)
{
String prefix = entry.getKey();
String namespace = entry.getValue();
EPackage ePackage = null;
if (extendedMetaData == null)
{
ePackage = packageRegistry.getEPackage(namespace);
}
else
{
ePackage = extendedMetaData.getPackage(namespace);
if (ePackage == null)
{
if (XMLResource.XML_SCHEMA_URI.equals(namespace))
{
ePackage = xmlSchemaTypePackage;
}
else
{
ePackage = extendedMetaData.demandPackage(namespace);
}
}
}
if (ePackage != null && !packages.containsKey(ePackage))
{
packages.put(ePackage, prefix);
}
prefixesToURIs.put(prefix, namespace);
}
}
/**
* A helper to encode namespace prefix mappings.
*/
protected static class NamespaceSupport
{
protected String[] namespace = new String [16 * 2];
protected int namespaceSize = 0;
protected int[] context = new int [8];
protected int currentContext = -1;
protected String[] prefixes = new String [16];
public void pushContext()
{
// extend the array, if necessary
if (currentContext + 1 == context.length)
{
int[] contextarray = new int [context.length * 2];
System.arraycopy(context, 0, contextarray, 0, context.length);
context = contextarray;
}
// push context
context[++currentContext] = namespaceSize;
}
public void popContext()
{
namespaceSize = context[currentContext--];
}
public void popContext(Map<String, EFactory> prefixesToFactories)
{
int oldNamespaceSize = namespaceSize;
for (int i = namespaceSize = context[currentContext--]; i < oldNamespaceSize; i += 2)
{
prefixesToFactories.remove(namespace[i]);
}
}
/**
* @param prefix prefix to declare
* @param uri uri that maps to the prefix
* @return true if the prefix existed in the current context and
* its uri has been remapped; false if prefix does not exist in the
* current context
*/
public boolean declarePrefix(String prefix, String uri)
{
// see if prefix already exists in current context
for (int i = namespaceSize; i > context[currentContext]; i -= 2)
{
if (namespace[i - 2].equals(prefix))
{
namespace[i - 1] = uri;
return true;
}
}
// resize array, if needed
if (namespaceSize == namespace.length)
{
String[] namespacearray = new String [namespaceSize * 2];
System.arraycopy(namespace, 0, namespacearray, 0, namespaceSize);
namespace = namespacearray;
}
// bind prefix to uri in current context
namespace[namespaceSize++] = prefix;
namespace[namespaceSize++] = uri;
return false;
}
public String getURI(String prefix)
{
// find prefix in current context
for (int i = namespaceSize; i > 0; i -= 2)
{
if (namespace[i - 2].equals(prefix))
{
return namespace[i - 1];
}
}
// prefix not found
return null;
}
public String getPrefix(String uri)
{
// find uri in current context
for (int i = namespaceSize; i > 0; i -= 2)
{
String knownURI = namespace[i - 1];
if ((knownURI != null)? knownURI.equals(uri) : uri == knownURI)
{
knownURI = getURI(namespace[i - 2]);
if ((knownURI != null)? knownURI.equals(uri) : uri == knownURI)
return namespace[i - 2];
}
}
// uri not found
return null;
}
public int getDeclaredPrefixCount()
{
return (namespaceSize - context[currentContext]) / 2;
}
public String getDeclaredPrefixAt(int index)
{
return namespace[context[currentContext] + index * 2];
} // getDeclaredPrefixAt(int):String
}// namespace context
public void setAnySimpleType(EClass type)
{
anySimpleType = type;
}
public String convertToString(EFactory factory, EDataType dataType, Object value)
{
if (extendedMetaData != null)
{
if (value instanceof List<?>)
{
List<?> list = (List<?>)value;
for (Object item : list)
{
updateQNamePrefix(factory, dataType, item, true);
}
return factory.convertToString(dataType, value);
}
else
{
return updateQNamePrefix(factory, dataType, value, false);
}
}
return factory.convertToString(dataType, value);
}
protected Object createFromString(EFactory eFactory, EDataType eDataType, String value)
{
Object obj = eFactory.createFromString(eDataType, value);
if (extendedMetaData != null)
{
if (obj instanceof List<?>)
{
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)obj;
for (int i = 0; i < list.size(); i++)
{
Object item = list.get(i);
Object replacement = updateQNameURI(item);
if (replacement != item)
{
list.set(i, replacement);
}
}
}
else
{
obj = updateQNameURI(obj);
}
}
return obj;
}
protected Object updateQNameURI(Object value)
{
if (value instanceof QName)
{
QName qName = (QName)value;
if (qName.getNamespaceURI().length() != 0)
{
throw new IllegalArgumentException("Curly brace notation is not a syntactically valid serialized representation for the QName '" + qName.toString() + "'");
}
String prefix = qName.getPrefix();
String namespace = getURI(prefix);
qName = new org.eclipse.emf.ecore.xml.type.internal.QName(namespace, qName.getLocalPart(), prefix);
if (qName.getPrefix().length() > 0 && namespace == null)
{
throw new IllegalArgumentException("The prefix '" + prefix + "' is not declared for the QName '" + qName.toString() + "'");
}
if (namespace == null)
{
seenEmptyStringMapping = true;
String uri = prefixesToURIs.get("");
if (uri != null)
{
prefixesToURIs.put("", namespace);
addNSDeclaration("", uri);
}
}
return qName;
}
else
{
return value;
}
}
/**
* @param factory
* @param dataType
* @param value a data value to be converted to string
* @param list if the value is part of the list of values
* @return if the value is not part of the list, return string corresponding to value,
* otherwise return null
*/
protected String updateQNamePrefix(EFactory factory, EDataType dataType, Object value, boolean list)
{
if (value instanceof QName)
{
QName qName = (QName)value;
String namespace = qName.getNamespaceURI();
String localPart = qName.getLocalPart();
if (namespace.length() == 0)
{
if (value instanceof org.eclipse.emf.ecore.xml.type.internal.QName)
{
((org.eclipse.emf.ecore.xml.type.internal.QName)qName).setPrefix("");
}
else if (qName.getPrefix().length() != 0)
{
throw new IllegalStateException("The null namespace cannot be bound to a non-null prefix '" + qName + "'");
}
return localPart;
}
String prefix = qName.getPrefix();
EPackage ePackage = extendedMetaData.getPackage(namespace);
if (ePackage == null)
{
int size = extendedMetaData.demandedPackages().size();
ePackage = extendedMetaData.demandPackage(namespace);
if (prefix.length() != 0 && extendedMetaData.demandedPackages().size() > size)
{
ePackage.setNsPrefix(prefix);
}
}
if (!namespace.equals(getNamespaceURI(prefix)))
{
prefix = getPrefix(ePackage, true);
if (value instanceof org.eclipse.emf.ecore.xml.type.internal.QName)
{
((org.eclipse.emf.ecore.xml.type.internal.QName)qName).setPrefix(prefix);
}
}
return list ? null : prefix.length() == 0 ? localPart : prefix + ':' + localPart;
}
return list ? null: factory.convertToString(dataType, value);
}
protected void addNSDeclaration(String prefix, String uri)
{
if (uri != null)
{
List<String> existingPrefixes = urisToPrefixes.get(uri);
if (existingPrefixes == null)
{
int lowerBound = 0;
int index = 1;
String newPrefix;
while (prefixesToURIs.containsKey(newPrefix = prefix + "_" + index))
{
lowerBound = index;
index <<= 1;
}
if (lowerBound != 0)
{
int upperBound = index;
while (lowerBound + 1 < upperBound)
{
index = (lowerBound + upperBound) >> 1;
if (prefixesToURIs.containsKey(prefix + "_" + index))
{
lowerBound = index;
}
else
{
upperBound = index;
}
}
newPrefix = prefix + "_" + (lowerBound + 1);
}
prefixesToURIs.put(newPrefix, uri);
}
}
}
public void setMustHavePrefix(boolean mustHavePrefix)
{
this.mustHavePrefix = mustHavePrefix;
}
}