diff options
Diffstat (limited to 'bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl')
9 files changed, 2723 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java new file mode 100644 index 0000000000..aac4555212 --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/BaseAssociationProvider.java @@ -0,0 +1,88 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMDataType; +import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNode; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryAssociationProvider; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + + +/** + * + */ +public abstract class BaseAssociationProvider implements ModelQueryAssociationProvider +{ + public BaseAssociationProvider() + { + } + + public CMNode getCMNode(Node node) + { + CMNode result = null; + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE : + { + result = getCMAttributeDeclaration((Attr)node); + break; + } + case Node.ELEMENT_NODE : + { + result = getCMElementDeclaration((Element)node); + break; + } + case Node.CDATA_SECTION_NODE : + case Node.TEXT_NODE : + { + result = getCMDataType((Text)node); + break; + } + } + return result; + } + + + public CMDataType getCMDataType(Text text) + { + CMDataType result = null; + Node parentNode = text.getParentNode(); + if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE) + { + CMElementDeclaration ed = getCMElementDeclaration((Element)parentNode); + result = ed.getDataType(); + } + return result; + } + + + public CMAttributeDeclaration getCMAttributeDeclaration(Attr attr) + { + CMAttributeDeclaration result = null; + Element element = attr.getOwnerElement(); + if (element != null) + { + CMElementDeclaration ed = getCMElementDeclaration(element); + if (ed != null) + { + result = (CMAttributeDeclaration)ed.getAttributes().getNamedItem(attr.getName()); + } + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java new file mode 100644 index 0000000000..99e1c0e432 --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentLoader.java @@ -0,0 +1,214 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceTable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * + */ +public class CMDocumentLoader +{ + protected Document document; + protected ModelQuery modelQuery; + protected CMDocumentManager cmDocumentManager; + protected boolean isInferredGrammarEnabled = true; + protected CMDocumentLoadingNamespaceTable namespaceTable; + protected int count = 0; + + public CMDocumentLoader(Document document, ModelQuery modelQuery) + { + this(document, modelQuery.getCMDocumentManager()); + } + + public CMDocumentLoader(Document document, CMDocumentManager cmDocumentManager) + { + this.document = document; + this.cmDocumentManager = cmDocumentManager; + } + + public void loadCMDocuments() + { + //System.out.println("----------loadCMDocuments ------------"); + long time = System.currentTimeMillis(); + + boolean walkDocument = false; + + cmDocumentManager.removeAllReferences(); + + String[] doctypeInfo = XMLAssociationProvider.getDoctypeInfo(document); + if (doctypeInfo != null) + { + // load the doctype if required + walkDocument = handleGrammar(doctypeInfo[0], doctypeInfo[1], "DTD"); + } + else + { + Element element = getRootElement(document); + if (element != null) + { + namespaceTable = new CMDocumentLoadingNamespaceTable(document); + namespaceTable.addElement(element); + if (namespaceTable.isNamespaceEncountered()) + { + walkDocument = true; + //System.out.println("isNamespaceAware"); + } + else + { + namespaceTable = null; + walkDocument = isInferredGrammarEnabled; + //System.out.println("is NOT namespaceAware"); + } + } + } + + if (walkDocument) + { + visitNode(document); + } + + //System.out.println("--- elapsed time (" + count + ") = " + (System.currentTimeMillis() - time)); + } + + + public boolean handleGrammar(String publicId, String systemId, String type) + { + boolean result = false; + + int status = cmDocumentManager.getCMDocumentStatus(publicId); + if (status == CMDocumentCache.STATUS_NOT_LOADED) + { + cmDocumentManager.addCMDocumentReference(publicId, systemId, type); + } + else if (status == CMDocumentCache.STATUS_ERROR) + { + result = true; + } + return result; + } + + + public void handleElement(Element element) + { + visitChildNodes(element); + } + + + public void handleElementNS(Element element) + { + namespaceTable.addElement(element); + visitChildNodes(element); + } + + + public void visitNode(Node node) + { + int nodeType = node.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) + { + count++; + + Element element = (Element)node; + if (namespaceTable == null) + { + handleElement(element); + } + else + { + handleElementNS(element); + } + } + else if (nodeType == Node.DOCUMENT_NODE) + { + visitChildNodes(node); + } + } + + + protected void visitChildNodes(Node node) + { + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) + { + visitNode(child); + } + } + + + protected class CMDocumentLoadingNamespaceTable extends NamespaceTable + { + protected List newNamespaceList; + + public CMDocumentLoadingNamespaceTable(Document document) + { + super(document); + } + + + public void addElement(Element element) + { + newNamespaceList = null; + super.addElement(element); + if (newNamespaceList != null) + { + for (Iterator i = newNamespaceList.iterator(); i.hasNext(); ) + { + NamespaceInfo info = (NamespaceInfo)i.next(); + handleGrammar(info.uri, info.locationHint, "XSD"); + } + } + } + + + protected void internalAddNamespaceInfo(String key, NamespaceInfo info) + { + super.internalAddNamespaceInfo(key, info); + if (newNamespaceList == null) + { + newNamespaceList = new ArrayList(); + } + newNamespaceList.add(info); + } + } + + + protected Element getRootElement(Document document) + { + Element result = null; + NodeList nodeList = document.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0 ; i < nodeListLength; i++) + { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) + { + result = (Element)node; + break; + } + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java new file mode 100644 index 0000000000..30dc411a30 --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentManagerImpl.java @@ -0,0 +1,321 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument; +import org.eclipse.wst.sse.core.internal.contentmodel.ContentModelManager; +import org.eclipse.wst.sse.core.internal.contentmodel.internal.annotation.AnnotationUtility; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManagerListener; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentReferenceProvider; +import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache; + + +/** + * + */ +public class CMDocumentManagerImpl implements CMDocumentManager +{ + protected CMDocumentCache cmDocumentCache; + protected CMDocumentReferenceProvider cmDocumentReferenceProvider; + protected List listenerList = new Vector(); + protected Hashtable propertyTable = new Hashtable(); + protected Hashtable publicIdTable = new Hashtable(); + + + public CMDocumentManagerImpl(CMDocumentCache cmDocumentCache, CMDocumentReferenceProvider cmDocumentReferenceProvider) + { + this.cmDocumentCache = cmDocumentCache; + this.cmDocumentReferenceProvider = cmDocumentReferenceProvider; + setPropertyEnabled(PROPERTY_AUTO_LOAD, true); + setPropertyEnabled(PROPERTY_USE_CACHED_RESOLVED_URI, false); + } + + + public CMDocumentCache getCMDocumentCache() + { + return cmDocumentCache; + } + + + public void setPropertyEnabled(String propertyName, boolean value) + { + propertyTable.put(propertyName, value ? "true" : "false"); + for (Iterator i = listenerList.iterator(); i.hasNext(); ) + { + CMDocumentManagerListener listener = (CMDocumentManagerListener)i.next(); + listener.propertyChanged(this, propertyName); + } + } + + + public boolean getPropertyEnabled(String propertyName) + { + Object object = propertyTable.get(propertyName); + return object != null && object.equals("true"); + } + + + public void addListener(CMDocumentManagerListener listener) + { + listenerList.add(listener); + cmDocumentCache.addListener(listener); + } + + + public void removeListener(CMDocumentManagerListener listener) + { + listenerList.remove(listener); + cmDocumentCache.removeListener(listener); + } + + + protected String lookupResolvedURI(String publicId) + { + String key = publicId != null ? publicId : ""; + return (String)publicIdTable.get(key); + } + + + protected String lookupOrCreateResolvedURI(String publicId, String systemId) + { + String resolvedURI = null; + + String key = publicId != null ? publicId : ""; + + if (getPropertyEnabled(PROPERTY_USE_CACHED_RESOLVED_URI)) + { + resolvedURI = (String)publicIdTable.get(key); + } + + if (resolvedURI == null) + { + resolvedURI = cmDocumentReferenceProvider.resolveGrammarURI(publicId, systemId); + if (resolvedURI == null) + { + resolvedURI = ""; + } + publicIdTable.put(key, resolvedURI); + } + + return resolvedURI; + } + + + public int getCMDocumentStatus(String publicId) + { + int status = CMDocumentCache.STATUS_NOT_LOADED; + String resolvedURI = lookupResolvedURI(publicId); + if (resolvedURI != null) + { + status = cmDocumentCache.getStatus(resolvedURI); + } + return status; + } + + + public CMDocument getCMDocument(String publicId) + { + CMDocument result = null; + String resolvedURI = lookupResolvedURI(publicId); + if (resolvedURI != null) + { + result = cmDocumentCache.getCMDocument(resolvedURI); + } + return result; + } + + + public CMDocument getCMDocument(String publicId, String systemId, String type) + { + CMDocument cmDocument = null; + String resolvedURI = null; + + if (getPropertyEnabled(PROPERTY_AUTO_LOAD)) + { + resolvedURI = lookupOrCreateResolvedURI(publicId, systemId); + } + else + { + resolvedURI = lookupResolvedURI(publicId); + } + + if (resolvedURI != null) + { + int status = cmDocumentCache.getStatus(resolvedURI); + if (status == CMDocumentCache.STATUS_LOADED) + { + cmDocument = cmDocumentCache.getCMDocument(resolvedURI); + } + else if (status == CMDocumentCache.STATUS_NOT_LOADED) + { + if (getPropertyEnabled(PROPERTY_AUTO_LOAD)) + { + cmDocument = loadCMDocument(publicId, resolvedURI, type, getPropertyEnabled(PROPERTY_ASYNC_LOAD)); + } + } + } + return cmDocument; + } + + /** + * @deprecated + */ + public CMDocument getCMDocument(String publicId, String resolvedURI) + { + CMDocument cmDocument = null; + + if (resolvedURI != null) + { + int status = cmDocumentCache.getStatus(resolvedURI); + if (status == CMDocumentCache.STATUS_LOADED) + { + cmDocument = cmDocumentCache.getCMDocument(resolvedURI); + } + else if (status == CMDocumentCache.STATUS_NOT_LOADED) + { + if (getPropertyEnabled(PROPERTY_AUTO_LOAD)) + { + cmDocument = loadCMDocument(publicId, resolvedURI, "", getPropertyEnabled(PROPERTY_ASYNC_LOAD)); + } + } + } + return cmDocument; + } + + public void addCMDocumentReference(String publicId, String systemId, String type) + { + String resolvedURI = lookupOrCreateResolvedURI(publicId, systemId); + if (resolvedURI != null && resolvedURI.length() > 0) + { + int status = cmDocumentCache.getStatus(resolvedURI); + if (status == CMDocumentCache.STATUS_NOT_LOADED) + { + loadCMDocument(publicId, resolvedURI, type, getPropertyEnabled(PROPERTY_ASYNC_LOAD)); + } + } + } + + + public void addCMDocument(String publicId, String systemId, String resolvedURI, String type, CMDocument cmDocument) + { + String key = publicId != null ? publicId : ""; + publicIdTable.put(key, resolvedURI); + cmDocumentCache.putCMDocument(resolvedURI, cmDocument); + } + + + protected CMDocument loadCMDocument(final String publicId, final String resolvedURI, final String type, boolean async) + { + CMDocument result = null; + + //System.out.println("about to build CMDocument(" + publicId + ", " + unresolvedURI + " = " + resolvedURI + ")"); + if (async) + { + cmDocumentCache.setStatus(resolvedURI, CMDocumentCache.STATUS_LOADING); + //Thread thread = new Thread(new AsyncBuildOperation(publicId, resolvedURI, type)); + //thread.start(); + Job job = new Job("loading " + resolvedURI) + { + public boolean belongsTo(Object family) + { + boolean result = (family == CMDocumentManager.class); + return result; + } + + protected IStatus run(IProgressMonitor monitor) + { + try + { + new AsyncBuildOperation(publicId, resolvedURI, type).run(); + } + catch (Exception e) + { + } + return Status.OK_STATUS; + } + }; + job.schedule(); + } + else + { + result = buildCMDocument(publicId, resolvedURI, type); + } + return result; + } + + + + protected class AsyncBuildOperation implements Runnable + { + protected String publicId; + protected String resolvedURI; + protected String type; + + public AsyncBuildOperation(String publicId, String resolvedURI, String type) + { + this.publicId = publicId; + this.resolvedURI = resolvedURI; + this.type = type; + } + + public void run() + { + buildCMDocument(publicId, resolvedURI, type); + } + } + + + public synchronized CMDocument buildCMDocument(String publicId, String resolvedURI, String type) + { + cmDocumentCache.setStatus(resolvedURI, CMDocumentCache.STATUS_LOADING); + + CMDocument result = null; + int x = 1; + x++; + if (resolvedURI != null && resolvedURI.length() > 0) + { + // TODO... pass the TYPE thru to the CMDocumentBuilder + result = ContentModelManager.getInstance().createCMDocument(resolvedURI, type); + } + if (result != null) + { + // load the annotation files for the document + if (publicId != null) + { + AnnotationUtility.loadAnnotationsForGrammar(publicId, result); + } + cmDocumentCache.putCMDocument(resolvedURI, result); + } + else + { + cmDocumentCache.setStatus(resolvedURI, CMDocumentCache.STATUS_ERROR); + } + return result; + } + + public void removeAllReferences() + { + // TODO... initiate a timed release of the entries in the CMDocumentCache + publicIdTable = new Hashtable(); + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java new file mode 100644 index 0000000000..52be1bede2 --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/CMDocumentReferenceImpl.java @@ -0,0 +1,42 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentReference; + +public class CMDocumentReferenceImpl implements CMDocumentReference +{ + protected String systemId; + protected String publicId; + + public CMDocumentReferenceImpl(String publicId, String systemId) + { + this.publicId = publicId; + this.systemId = systemId; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + public String toString() + { + return "[" + publicId + ", " + systemId + "]"; + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java new file mode 100644 index 0000000000..18200c8719 --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/InferredGrammarBuildingCMDocumentLoader.java @@ -0,0 +1,189 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import java.util.Hashtable; + +import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument; +import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.internal.modelqueryimpl.InferredGrammarFactory; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +/** + * + */ +public class InferredGrammarBuildingCMDocumentLoader extends CMDocumentLoader +{ + protected CMElementDeclaration inferredCMElementDeclaration; + protected CMDocument inferredCMDocument; + protected InferredGrammarFactory inferredGrammarFactory; + protected Hashtable createdCMDocumentTable; + + public InferredGrammarBuildingCMDocumentLoader(Document document, ModelQuery modelQuery) + { + this(document, modelQuery.getCMDocumentManager()); + } + + public InferredGrammarBuildingCMDocumentLoader(Document document, CMDocumentManager cmDocumentManager) + { + super(document, cmDocumentManager); + createdCMDocumentTable = new Hashtable(); + inferredGrammarFactory = new InferredGrammarFactory(); + } + + + public void loadCMDocuments() + { + //System.out.println("----------loadCMDocuments ------------"); + if (inferredGrammarFactory != null) + { + long time = System.currentTimeMillis(); + super.loadCMDocuments(); + //System.out.println("--- elapsed time (" + count + ") = " + (System.currentTimeMillis() - time)); + //inferredGrammarFactory.debugPrint(createdCMDocumentTable.values()); + } + + } + + public void handleElement(Element element) + { + CMElementDeclaration parentInferredCMElementDeclaration = inferredCMElementDeclaration; + + if (inferredCMDocument == null) + { + String cacheKey = "inferred-document"; + inferredCMDocument = inferredGrammarFactory.createCMDocument(""); + cmDocumentManager.addCMDocument("", "", cacheKey, "DTD", inferredCMDocument); + createdCMDocumentTable.put(cacheKey, inferredCMDocument); + } + + inferredCMElementDeclaration = inferredGrammarFactory.createCMElementDeclaration(inferredCMDocument, element, false); + + if (parentInferredCMElementDeclaration != null) + { + inferredGrammarFactory.createCMContent(inferredCMDocument, parentInferredCMElementDeclaration, inferredCMDocument, inferredCMElementDeclaration, false, null); + } + + + visitChildNodes(element); + + // reset the 'current' state to inital values + inferredCMElementDeclaration = parentInferredCMElementDeclaration; + } + + + public void handleElementNS(Element element) + { + CMDocument parentInferredCMDocument = inferredCMDocument; + CMElementDeclaration parentInferredCMElementDeclaration = inferredCMElementDeclaration; + + inferredCMDocument = null; + inferredCMElementDeclaration = null; + + // by adding the element to the namespaceTable, handleGrammar() will get called for any schema references + if (element.getParentNode() != document) + { + namespaceTable.addElement(element); + } + + String prefix = element.getPrefix(); + String uri = namespaceTable.getURIForPrefix(prefix); + + if (uri == null && element.getParentNode() == document) + { + // when this is the root element + // we need to add an implied "no namespace schema location" + uri = "ommitted-namespace"; + namespaceTable.addNamespaceInfo(prefix, uri, ""); + } + + // here's where we update the inferred grammar if required + // + boolean createCMElementDeclaration = true; + + boolean isLocal = (uri == null && prefix == null); + if (isLocal) + { + if (parentInferredCMDocument == null) + { + // this is a local element... and the parent is not inferred (e.g) it has a known grammar + // so we don't need to create an element declaration for this element + createCMElementDeclaration = false; + } + else + { + if (uri == null) + { + uri = "ommitted-namespace"; + } + } + } + + if (createCMElementDeclaration) + { + if (isLocal) + { + inferredCMDocument = parentInferredCMDocument; + inferredCMElementDeclaration = inferredGrammarFactory.createCMElementDeclaration(inferredCMDocument, element, true); + } + else + { + boolean createCMDocument = false; + + String cacheKey = "inferred-document" + uri; + inferredCMDocument = (CMDocument)createdCMDocumentTable.get(cacheKey); + + if (inferredCMDocument == null) + { + // we don't have an inferred document for this uri yet... let's see of we need one + int status = cmDocumentManager.getCMDocumentStatus(uri); + if (status == CMDocumentCache.STATUS_NOT_LOADED || status == CMDocumentCache.STATUS_ERROR) + { + // the cache does not contain a 'proper' CMDocument for this uri + // so we need to create an inferred one + createCMDocument = true; + } + } + + if (createCMDocument) + { + //System.out.println("encountered element {" + element.getNodeName() + "} ... creating inferred CMDocument for " + uri); + inferredCMDocument = inferredGrammarFactory.createCMDocument(uri); + cmDocumentManager.addCMDocument(uri, "", cacheKey, "XSD", inferredCMDocument); + createdCMDocumentTable.put(cacheKey, inferredCMDocument); + } + + if (inferredCMDocument != null) + { + inferredCMElementDeclaration = inferredGrammarFactory.createCMElementDeclaration(inferredCMDocument, element, false); + } + } + + if (parentInferredCMElementDeclaration != null) + { + inferredGrammarFactory.createCMContent(parentInferredCMDocument, parentInferredCMElementDeclaration, inferredCMDocument, inferredCMElementDeclaration, isLocal, uri); + } + } + + visitChildNodes(element); + + // reset the 'current' state to inital values + inferredCMElementDeclaration = parentInferredCMElementDeclaration; + inferredCMDocument = parentInferredCMDocument; + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java new file mode 100644 index 0000000000..2f687a81de --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryActionHelper.java @@ -0,0 +1,570 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument; +import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMGroup; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNode; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNodeList; +import org.eclipse.wst.sse.core.internal.contentmodel.internal.util.CMValidator; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryAction; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * + */ +public class ModelQueryActionHelper +{ + protected ModelQueryImpl modelQuery; + + protected static class Action implements ModelQueryAction + { + public int kind; + public int startIndex; + public int endIndex; + public Node parent; + public CMNode cmNode; + public Object userData; + + public Action(int kind, Node parent, CMNode cmNode) + { + this.kind = kind; + this.parent = parent; + this.cmNode = cmNode; + } + + public Action(int kind, Node parent, CMNode cmNode, int startIndex, int endIndex) + { + this.kind = kind; + this.parent = parent; + this.cmNode = cmNode; + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + public int getKind() + { + return kind; + } + + public int getStartIndex() + { + return startIndex; + } + + public int getEndIndex() + { + return endIndex; + } + + public Node getParent() + { + return parent; + } + + public CMNode getCMNode() + { + return cmNode; + } + + public Object getUserData() + { + return userData; + } + + public void setUserData(Object object) + { + userData = object; + } + + public void performAction() + { + } + } + + + public ModelQueryActionHelper(ModelQueryImpl modelQuery) + { + this.modelQuery = modelQuery; + } + + + public void getAllActions(Element parent, CMElementDeclaration ed, int validityChecking, List actionList) + { + } + + + // insert actions + // + public void getInsertActions(Element parent, CMElementDeclaration ed, int index, int includeOptions, int validityChecking, List actionList) + { + if ((includeOptions & ModelQuery.INCLUDE_ATTRIBUTES) != 0) + { + getInsertAttributeActions(parent, ed, validityChecking, actionList); + } + includeOptions &= ~ModelQuery.INCLUDE_ATTRIBUTES; + if ((includeOptions & ModelQuery.INCLUDE_CHILD_NODES) != 0) + { + if (index != -1) + { + getInsertChildNodeActionsAtIndex(parent, ed, index, includeOptions, validityChecking, actionList); + } + else + { + getInsertChildNodeActions(parent, ed, includeOptions, validityChecking, actionList); + } + } + } + + + + protected void getInsertAttributeActions(Element parent, CMElementDeclaration ed, int validityChecking, List actionList) + { + // get actions for each insertable attribute + // + List availableAttributeList = modelQuery.getAvailableContent(parent, ed, ModelQuery.INCLUDE_ATTRIBUTES); + + for (Iterator i = availableAttributeList.iterator(); i.hasNext(); ) + { + CMAttributeDeclaration ad = (CMAttributeDeclaration)i.next(); + if (modelQuery.canInsert(parent, ed, ad, 0, validityChecking)) + { + Action action = new Action(ModelQueryAction.INSERT, parent, ad); + actionList.add(action); + } + } + } + + + protected void getInsertChildNodeActionsAtIndex(Element parent, CMElementDeclaration ed, int index, int includeOptions, int validityChecking, List actionList) + { + // get actions for each insertable attribute + // + int size = parent.getChildNodes().getLength(); + if (index <= size) + { + List contentSpecificationList = modelQuery.getValidator().createContentSpecificationList(parent, ed); + List availableChildNodeList = modelQuery.getAvailableContent(parent, ed, includeOptions); + + boolean isSimpleChoice = isSimpleChoiceGroupContentModel(ed); + + for (Iterator i = availableChildNodeList.iterator(); i.hasNext(); ) + { + CMNode cmNode = (CMNode)i.next(); + if (isSimpleChoice || modelQuery.canInsert(parent, ed, cmNode, index, validityChecking, contentSpecificationList)) + { + Action action = new Action(ModelQueryAction.INSERT, parent, cmNode, index, index); + actionList.add(action); + } + } + } + } + + + protected boolean isSimpleChoiceGroupContentModel(CMElementDeclaration ed) + { + boolean result = false; + CMNode cmNode = ed.getContent(); + if (cmNode != null && cmNode.getNodeType() == CMNode.GROUP) + { + CMGroup cmGroup = (CMGroup)cmNode; + if (cmGroup.getOperator() == CMGroup.CHOICE && cmGroup.getMaxOccur() == -1) + { + result = true; + CMNodeList list = cmGroup.getChildNodes(); + for (int i = list.getLength() - 1; i >= 0; i--) + { + if (list.item(i).getNodeType() != CMNode.ELEMENT_DECLARATION) + { + result = false; + break; + } + } + } + } + return result; + } + + + protected void getInsertChildNodeActions(Element parent, CMElementDeclaration ed, int includeOptions, int validityChecking, List actionList) + { + int size = parent.getChildNodes().getLength(); + List contentSpecificationList = modelQuery.getValidator().createContentSpecificationList(parent, ed); + List availableChildNodeList = modelQuery.getAvailableContent(parent, ed, includeOptions); + + boolean isSimpleChoice = isSimpleChoiceGroupContentModel(ed); + + for (Iterator iterator = availableChildNodeList.iterator(); iterator.hasNext(); ) + { + CMNode cmNode = (CMNode)iterator.next(); + for (int i = size; i >= 0; i--) + { + if (isSimpleChoice || modelQuery.canInsert(parent, ed, cmNode, i, validityChecking, contentSpecificationList)) + { + Action action = new Action(ModelQueryAction.INSERT, parent, cmNode, i, i); + actionList.add(action); + break; + } + } + } + } + + public void getInsertActions(Document parent, CMDocument cmDocument, int index, int includeOptions, int validityChecking, List actionList) + { + // get the root element and doctype index (if any) + // + int doctypeIndex = -1; + DocumentType doctype = null; + Element rootElement = null; + NodeList nodeList = parent.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) + { + Node childNode = nodeList.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) + { + rootElement = (Element)childNode; + break; + } + else if (childNode.getNodeType() == Node.DOCUMENT_TYPE_NODE) + { + doctype = (DocumentType)childNode; + doctypeIndex = i; + } + } + + // make sure that root elements are only added after the doctype (if any) + if (rootElement == null && index > doctypeIndex) + { + CMNamedNodeMap map = cmDocument.getElements(); + int mapLength = map.getLength(); + for (int i = 0; i < mapLength; i++) + { + CMNode cmNode = map.item(i); + + boolean canAdd = true; + if (validityChecking == ModelQuery.VALIDITY_STRICT) + { + canAdd = doctype == null || doctype.getName().equals(cmNode.getNodeName()); + } + + if (canAdd) + { + Action action = new Action(ModelQueryAction.INSERT, parent, cmNode, index, index); + actionList.add(action); + } + } + } + } + + + + public void getInsertChildNodeActionTable(Element parent, CMElementDeclaration ed, int validityChecking, Hashtable actionTable) + { + } + + + public void getReplaceActions(Element parent, CMElementDeclaration ed, int includeOptions, int validityChecking, List actionList) + { + CMValidator.MatchModelNode matchModelNode = modelQuery.getValidator().getMatchModel(ed, parent); + if (matchModelNode != null) + { + MatchModelVisitor visitor = new MatchModelVisitor(parent, actionList); + visitor.visitMatchModelNode(matchModelNode); + } + } + + public void getReplaceActions(Element parent, CMElementDeclaration ed, List selectedChildren, int includeOptions, int validityChecking, List actionList) + { + int[] range = getRange(parent, selectedChildren); + if (range != null) + { + if (isContiguous(parent, range, selectedChildren)) + { + List tempList = new Vector(); + getReplaceActions(parent, ed, includeOptions, validityChecking, tempList); + if ((includeOptions & ModelQuery.INCLUDE_ENCLOSING_REPLACE_ACTIONS) != 0) + { + removeActionsNotContainingRange(tempList, range[0], range[1]); + } + else + { + removeActionsNotMatchingRange(tempList, range[0], range[1]); + } + actionList.addAll(tempList); + } + } + + if (selectedChildren.size() == 1) + { + Node node = (Node)selectedChildren.get(0); + if (node.getNodeType() == Node.ELEMENT_NODE) + { + Element childElement = (Element)node; + CMNode childEd = modelQuery.getCMElementDeclaration(childElement); + if (childEd != null) + { + + CMNode childOrigin= modelQuery.getOrigin(childElement); + + CMNodeList cmNodeList = childOrigin != null ? + (CMNodeList)childOrigin.getProperty("SubstitutionGroup") : + (CMNodeList)childEd.getProperty("SubstitutionGroup"); + + if (cmNodeList != null && cmNodeList.getLength() > 1) + { + int replaceIndex = getIndex(parent, childElement); + String childEdName = childEd.getNodeName(); + for (int i = 0; i < cmNodeList.getLength(); i++) + { + CMNode substitution = cmNodeList.item(i); + if (!substitution.getNodeName().equals(childEdName) && !Boolean.TRUE.equals(substitution.getProperty("Abstract"))) + { + Action action = new Action(ModelQueryAction.REPLACE, parent, cmNodeList.item(i), replaceIndex, replaceIndex); + actionList.add(action); + } + } + } + } + } + } + } + + + // returns true if the selected nodes are contiguous + // + protected boolean isContiguous(Element parent, int[] range, List selectedNodeList) + { + boolean result = true; + NodeList nodeList = parent.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = range[0]; i < range[1]; i++) + { + Node node = nodeList.item(i); + if (!isWhitespaceNode(node) && !selectedNodeList.contains(node)) + { + result = false; + break; + } + } + return result; + } + + + protected int[] getRange(Element parent, List list) + { + int[] result = null; + int first = -1; + int last = -1; + + NodeList nodeList = parent.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) + { + Node node = nodeList.item(i); + if (list.contains(node)) + { + first = (first == -1) ? i : Math.min(first, i); + last = Math.max(last, i); + } + } + + if (first != -1 && last!= -1) + { + result = new int[2]; + result[0] = first; + result[1] = last; + } + return result; + } + + + protected boolean isWhitespaceNode(Node node) + { + return node.getNodeType() == Node.TEXT_NODE && + node.getNodeValue().trim().length() == 0; + } + + + protected int getIndex(Node parentNode, Node child) + { + NodeList nodeList = parentNode.getChildNodes(); + int index = -1; + int size = nodeList.getLength(); + for (int i = 0; i < size; i++) + { + if (nodeList.item(i) == child) + { + index = i; + break; + } + } + return index; + } + + + protected boolean isActionContainingRange(ModelQueryAction action, int startIndex, int endIndex) + { + int actionStartIndex = action.getStartIndex(); + int actionEndIndex = action.getEndIndex(); + + return (actionStartIndex <= startIndex && + actionEndIndex >= endIndex); + } + + + protected boolean isActionMatchingRange(ModelQueryAction action, int startIndex, int endIndex) + { + int actionStartIndex = action.getStartIndex(); + int actionEndIndex = action.getEndIndex(); + return (actionStartIndex == startIndex && + actionEndIndex == endIndex); + } + + + protected void removeActionsNotContainingRange(List actionList, int startIndex, int endIndex) + { + for (int i = actionList.size() - 1; i >= 0; i--) + { + ModelQueryAction action = (ModelQueryAction)actionList.get(i); + if (!isActionContainingRange(action, startIndex, endIndex)) + { + actionList.remove(i); + } + } + } + + + protected void removeActionsNotMatchingRange(List actionList, int startIndex, int endIndex) + { + for (int i = actionList.size() - 1; i >= 0; i--) + { + ModelQueryAction action = (ModelQueryAction)actionList.get(i); + if (!isActionMatchingRange(action, startIndex, endIndex)) + { + actionList.remove(i); + } + } + } + + + public static class MatchModelVisitor + { + int indent; + int elementIndex; + Node parent; + List actionList; + + public MatchModelVisitor(Node parent, List actionList) + { + this.parent = parent; + this.actionList = actionList; + } + + public int indexOfNextElement(int start) + { + NodeList nodeList = parent.getChildNodes(); + int length = nodeList.getLength(); + int result = length; + for (int i = start; i < length; i++) + { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) + { + result = i; + break; + } + } + return result; + } + + public void visitMatchModelNode(CMValidator.MatchModelNode matchModelNode) + { + int startIndex = indexOfNextElement(elementIndex); + + String cmNodeName = matchModelNode.cmNode != null ? matchModelNode.cmNode.getNodeName() : "null"; + //printIndented(indent, "+MatchModelNode : " + cmNodeName + " " + startIndex); + + indent += 2; + for (Iterator iterator = matchModelNode.children.iterator(); iterator.hasNext(); ) + { + CMValidator.MatchModelNode child = (CMValidator.MatchModelNode)iterator.next(); + visitMatchModelNode(child); + } + indent -= 2; + + if (matchModelNode.cmNode != null) + { + int nodeType = matchModelNode.cmNode.getNodeType(); + if (nodeType == CMNode.GROUP) + { + CMGroup group = (CMGroup)matchModelNode.cmNode; + if (group.getOperator() == CMGroup.CHOICE) + { + addReplaceActions(matchModelNode, group, startIndex, elementIndex - 1); + } + } + else if (nodeType == CMNode.ELEMENT_DECLARATION) + { + elementIndex = startIndex + 1; + } + //printIndented(indent, "-MatchModelNode : " + cmNodeName + " " + (elementIndex - 1)); + } + } + + public void addReplaceActions(CMValidator.MatchModelNode matchModelNode, CMGroup group, int startIndex, int endIndex) + { + CMNode excludeCMNode = null; + if (matchModelNode.children.size() > 0) + { + CMValidator.MatchModelNode child = (CMValidator.MatchModelNode)matchModelNode.children.get(0); + excludeCMNode = child.cmNode; + } + + CMNodeList nodeList = group.getChildNodes(); + int size = nodeList.getLength(); + for (int i = 0; i < size; i++) + { + CMNode alternative = nodeList.item(i); + if (alternative != excludeCMNode) + { + Action action = new Action(ModelQueryAction.REPLACE, parent, alternative, startIndex, endIndex); + actionList.add(action); + } + } + } + } + + //public static void printIndented(int indent, String string) + //{ + // for (int i = 0; i < indent; i++) + // { + // System.out.print(" "); + // } + // System.out.println(string); + //} +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java new file mode 100644 index 0000000000..befc4043de --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/ModelQueryImpl.java @@ -0,0 +1,848 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.wst.sse.core.internal.contentmodel.CMAnyElement; +import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMDataType; +import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument; +import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMGroup; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNode; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNodeList; +import org.eclipse.wst.sse.core.internal.contentmodel.internal.modelqueryimpl.*; +import org.eclipse.wst.sse.core.internal.contentmodel.internal.util.CMDataTypeValueHelper; +import org.eclipse.wst.sse.core.internal.contentmodel.internal.util.DOMValidator; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryAssociationProvider; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.extension.ModelQueryExtensionManager; +import org.eclipse.wst.sse.core.internal.contentmodel.util.CMVisitor; +import org.eclipse.wst.sse.core.internal.contentmodel.util.DOMNamespaceHelper; +import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceTable; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + + +/** + * This class implements a large portion of the ModelQuery interfaces. + * Some work is delegated to the DOMHelper, CMDocumentManager, and DOMValidator. + */ +public class ModelQueryImpl implements ModelQuery +{ + protected ModelQueryAssociationProvider modelQueryAssociationProvider; + protected ModelQueryActionHelper modelQueryActionHelper; + protected DOMValidator validator; + protected ModelQueryExtensionManagerImpl extensionManager; + protected CMDataTypeValueHelper valueHelper; + protected int editMode = EDIT_MODE_CONSTRAINED_STRICT; + + public ModelQueryImpl(ModelQueryAssociationProvider modelQueryAssociationProvider) + { + this.modelQueryAssociationProvider = modelQueryAssociationProvider; + modelQueryActionHelper = createModelQueryActionHelper(); + validator = new DOMValidator(); + extensionManager = new ModelQueryExtensionManagerImpl(); + valueHelper = new CMDataTypeValueHelper(); + } + + public int getEditMode() + { + return editMode; + } + + public void setEditMode(int editMode) + { + this.editMode =editMode; + } + + + // factory methods + public ModelQueryActionHelper createModelQueryActionHelper() + { + return new ModelQueryActionHelper(this); + } + + public DOMValidator getValidator() + { + return validator; + } + + public CMDocument getCorrespondingCMDocument(Node node) + { + return modelQueryAssociationProvider.getCorrespondingCMDocument(node); + } + + public CMNode getCMNode(Node node) + { + return modelQueryAssociationProvider.getCMNode(node); + } + + public CMDataType getCMDataType(Text text) + { + return modelQueryAssociationProvider.getCMDataType(text); + } + + public CMAttributeDeclaration getCMAttributeDeclaration(Attr attr) + { + return modelQueryAssociationProvider.getCMAttributeDeclaration(attr); + } + + public CMElementDeclaration getCMElementDeclaration(Element element) + { + return modelQueryAssociationProvider.getCMElementDeclaration(element); + } + + public CMDocumentManager getCMDocumentManager() + { + CMDocumentManager result = null; + if (modelQueryAssociationProvider instanceof XMLAssociationProvider) + { + XMLAssociationProvider xmlAssociationProvider = (XMLAssociationProvider)modelQueryAssociationProvider; + result = xmlAssociationProvider.getCMDocumentManager(); + } + return result; + } + + + /** + * @deprected - use 3 arg version below + */ + public List getCMDocumentList(Element element, String uri) + { + return Collections.EMPTY_LIST; + } + + public List getCMDocumentList(Element element, CMElementDeclaration ed, String uri) + { + List result = new Vector(); + if (modelQueryAssociationProvider instanceof XMLAssociationProvider) + { + XMLAssociationProvider xmlAssociationProvider = (XMLAssociationProvider)modelQueryAssociationProvider; + + // todo... revist... handle each ##thing explicitly + // + if (uri == null) + { + uri = "##any"; + } + + if (uri.equals("##targetNamespace")) + { + CMDocument cmDocument = (CMDocument)ed.getProperty("CMDocument"); + if (cmDocument != null) + { + result.add(cmDocument); + } + } + else if (uri.equals("##any") || uri.equals("##other")) + { + String excludedURI = null; + if (uri.equals("##other")) + { + CMDocument cmDocument = (CMDocument)ed.getProperty("CMDocument"); + if (cmDocument != null) + { + excludedURI = (String)cmDocument.getProperty("http://org.eclipse.wst/cm/properties/targetNamespaceURI"); + } + } + + // in this case we should consider all of the schema related to this document + // + NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument()); + namespaceTable.addElementLineage(element); + List list = namespaceTable.getNamespaceInfoList(); + for (Iterator i = list.iterator(); i.hasNext();) + { + NamespaceInfo info = (NamespaceInfo)i.next(); + if (info.uri != null && !info.uri.equals(excludedURI)) + { + CMDocument document = xmlAssociationProvider.getCMDocument(info.uri, info.locationHint, "XSD"); + if (document != null) + { + result.add(document); + } + } + } + } + else + { + CMDocument document = xmlAssociationProvider.getCMDocument(element, uri); + if (document != null) + { + result.add(document); + } + } + } + return result; + } + + + public CMDocument getCMDocument(Element element, String uri) + { + + CMDocument result = null; + if (modelQueryAssociationProvider instanceof XMLAssociationProvider) + { + XMLAssociationProvider xmlAssociationProvider = (XMLAssociationProvider)modelQueryAssociationProvider; + result = xmlAssociationProvider.getCMDocument(element, uri); + } + //ContentModelManager.println("ModelQueryImpl.getCMDocument(" + element.getNodeName() + ", " + uri + ") = " + result); + return result; + } + + public boolean isContentValid(Element element) + { + CMElementDeclaration ed = getCMElementDeclaration(element); + return isContentValid(ed, element); + } + + public boolean isContentValid(CMElementDeclaration ed, Element element) + { + boolean result = true; + if (ed != null) + { + // first check to see if all the required attributes are present + // + CMNamedNodeMap map = ed.getAttributes(); + int mapLength = map.getLength(); + for (int i = 0; i < mapLength; i++) + { + CMAttributeDeclaration ad = (CMAttributeDeclaration)map.item(i); + String attributeName = DOMNamespaceHelper.computeName(ad, element, null); + if (ad.getUsage() == CMAttributeDeclaration.REQUIRED) + { + Attr attr = element.getAttributeNode(attributeName); + if (attr == null) + { + result = false; + break; + } + } + } + + // now check to see of the children validate properly + // + if (result) + { + CMNode[] originArray = getOriginArray(element); + result = originArray != null && originArray.length == element.getChildNodes().getLength(); + } + } + return result; + } + + + public CMNode getOrigin(Node node) + { + CMNode result = null; + // todo... make sure parent is right + // + Node parentNode = getParentOrOwnerNode(node); + if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE) + { + Element parentElement = (Element)parentNode; + CMNode[] array = getOriginArray(parentElement); + if (array != null) + { + int index = getIndexOfNode(parentElement.getChildNodes(), node); + if (index < array.length) + { + result = array[index]; + } + } + } + return result; + } + + public CMNode[] getOriginArray(Element element) + { + CMElementDeclaration ed = getCMElementDeclaration(element); + return (ed != null) ? getValidator().getOriginArray(ed, element) : null; + } + + public int getIndexOfNode(NodeList nodeList, Node node) + { + int result = -1; + int size = nodeList.getLength(); + for (int i = 0; i < size; i++) + { + if (nodeList.item(i) == node) + { + result = i; + break; + } + } + return result; + } + + + /** + * Returns a list of all CMNode 'meta data' that may be potentially added to the element. + */ + public List getAvailableContent(Element element, CMElementDeclaration ed, int includeOptions) + { + AvailableContentCMVisitor visitor = new AvailableContentCMVisitor(element, ed); + List list = visitor.computeAvailableContent(includeOptions); + if (extensionManager != null) + { + extensionManager.filterAvailableElementContent(list, element, ed); + } + return list; + } + + + public boolean canInsert(Element parent, CMNode cmNode, int index, int validityChecking) + { + boolean result = true; + CMElementDeclaration ed = getCMElementDeclaration(parent); + if (ed != null) + { + result = canInsert(parent, ed, cmNode, index, validityChecking); + } + return result; + } + + + public boolean canInsert(Element parent, CMElementDeclaration ed, CMNode cmNode, int index, int validityChecking) + { + return canInsert(parent, ed, cmNode, index, validityChecking, null); + } + + protected boolean canInsert(Element parent, CMElementDeclaration ed, CMNode cmNode, int index, int validityChecking, Object reuseableData) + { + boolean result = true; + switch (cmNode.getNodeType()) + { + case CMNode.ATTRIBUTE_DECLARATION : + { + String attributeName = DOMNamespaceHelper.computeName(cmNode, parent, null); + result = parent.getAttributeNode(attributeName) == null; + break; + } + case CMNode.ELEMENT_DECLARATION : + case CMNode.GROUP : + { + if (validityChecking == VALIDITY_STRICT) + { + // create list + List contentSpecificationList = null; + if (reuseableData != null) + { + contentSpecificationList = (List)reuseableData; + } + else + { + contentSpecificationList = getValidator().createContentSpecificationList(parent, ed); + } + result = getValidator().canInsert(ed, contentSpecificationList, index, cmNode); + } + break; + } + case CMNode.DATA_TYPE : + { + int contentType = ed.getContentType(); + result = (contentType == CMElementDeclaration.MIXED || + contentType == CMElementDeclaration.PCDATA || + contentType == CMElementDeclaration.ANY); + break; + } + default : + { + result = false; + break; + } + } + return result; + } + + public boolean canInsert(Element parent, List cmNodeList, int index, int validityChecking) + { + // todo + return true; + } + + + public boolean canRemove(Node node, int validityChecking) + { + boolean result = true; + if (validityChecking == VALIDITY_STRICT) + { + int nodeType = node.getNodeType(); + switch (nodeType) + { + case Node.ATTRIBUTE_NODE: + { + CMAttributeDeclaration ad = getCMAttributeDeclaration((Attr)node); + if (ad != null) + { + result = (ad.getUsage() == CMAttributeDeclaration.OPTIONAL); + } + break; + } + case Node.ELEMENT_NODE: + { + Node parentNode = node.getParentNode(); + if (parentNode.getNodeType() == Node.ELEMENT_NODE) + { + Element parentElement = (Element)parentNode; + CMElementDeclaration ed = getCMElementDeclaration(parentElement); + if (ed != null) + { + List contentSpecificationList = getValidator().createContentSpecificationList(parentElement, ed); + int index = getIndexOfNode(parentElement.getChildNodes(), node); + result = getValidator().canRemove(ed, contentSpecificationList, index); + } + } + break; + } + } + } + return result; + } + + + public boolean canRemove(List nodeList, int validityChecking) + { + boolean result = true; + + if (validityChecking == VALIDITY_STRICT) + { + Element parentElement = null; + List childList = null; + + for (Iterator i = nodeList.iterator(); i.hasNext(); ) + { + Node node = (Node)i.next(); + + if (parentElement == null) + { + parentElement = getParentOrOwnerElement(node); + } + else if (parentElement != getParentOrOwnerElement(node)) + { + // make sure the parent are the same + result = false; + break; + } + + if (parentElement == null) + { + result = true; + break; + } + + int nodeType = node.getNodeType(); + if (nodeType == Node.ATTRIBUTE_NODE) + { + if (!canRemove(node, validityChecking)) + { + result = false; + break; + } + } + else + { + if (childList == null) + { + childList = nodeListToList(parentElement.getChildNodes()); + } + childList.remove(node); + } + } + + if (result && childList != null) + { + CMElementDeclaration ed = getCMElementDeclaration(parentElement); + if (ed != null) + { + List contentSpecificationList = getValidator().createContentSpecificationList(childList, ed); + result = getValidator().isValid(ed, contentSpecificationList); + } + } + } + + return result; + } + + public boolean canReplace(Element parent, int startIndex, int endIndex, CMNode cmNode, int validityChecking) + { + return true; + } + + public boolean canReplace(Element parent, int startIndex, int endIndex, List cmNodeList, int validityChecking) + { + return true; + } + + /** + * This method is experimental... use at your own risk + */ + public boolean canWrap(Element childElement, CMElementDeclaration wrapElement, int validityChecking) + { + boolean result = true; + Node parentNode = childElement.getParentNode(); + if (parentNode.getNodeType() == Node.ELEMENT_NODE) + { + Element parentElement = (Element)parentNode; + CMElementDeclaration parentEd = getCMElementDeclaration(parentElement); + if (parentEd != null) + { + if (validityChecking == VALIDITY_STRICT) + { + int index = getIndexOfNode(parentElement.getChildNodes(), childElement); + + List contentSpecificationList = getValidator().createContentSpecificationList(parentElement, parentEd); + List subList = contentSpecificationList.subList(index, index + 1); + result = getValidator().canReplace(parentEd, contentSpecificationList, index, index, wrapElement); + if (result) + { + result = getValidator().isValid(wrapElement, subList); + } + } + } + } + else + { + result = false; + } + return result; + } + + public void getInsertActions(Element parent, CMElementDeclaration ed, int index, int includeOptions, int validityChecking, List actionList) + { + modelQueryActionHelper.getInsertActions(parent, ed, index, includeOptions, validityChecking, actionList); + } + + public void getInsertActions(Document parent, CMDocument cmDocument, int index, int includeOptions, int validityChecking, List actionList) + { + modelQueryActionHelper.getInsertActions(parent, cmDocument, index, includeOptions, validityChecking, actionList); + } + + public void getReplaceActions(Element parent, CMElementDeclaration ed, int includeOptions, int validityChecking, List actionList) + { + modelQueryActionHelper.getReplaceActions(parent, ed, includeOptions, validityChecking, actionList); + } + + public void getReplaceActions(Element parent, CMElementDeclaration ed, List selectedChildren, int includeOptions, int validityChecking, List actionList) + { + modelQueryActionHelper.getReplaceActions(parent, ed, selectedChildren, includeOptions, validityChecking, actionList); + } + + public void getInsertChildNodeActionTable(Element parent, CMElementDeclaration ed, int validityChecking, Hashtable actionTable) + { + modelQueryActionHelper.getInsertChildNodeActionTable(parent, ed, validityChecking, actionTable); + } + + public void getActionTable(Element parent, CMElementDeclaration ed, int index, int validityChecking, Hashtable actionTable) + { + //modelQueryActionHelper.getAllActions(parent, ed, validityChecking, actionList); + } + + + // some helper methods + // + protected Node getParentOrOwnerNode(Node node) + { + return (node.getNodeType() == Node.ATTRIBUTE_NODE) ? + ((Attr)node).getOwnerElement() : + node.getParentNode(); + } + + protected Element getParentOrOwnerElement(Node node) + { + Node parent = getParentOrOwnerNode(node); + return (parent.getNodeType() == Node.ELEMENT_NODE) ? (Element)parent : null; + } + + + protected List nodeListToList(NodeList nodeList) + { + int size = nodeList.getLength(); + Vector v = new Vector(size); + for (int i = 0; i < size; i++) + { + v.add(nodeList.item(i)); + } + return v; + } + + /** + protected List getCMNodeList(NodeList nodeList) + { + int size = nodeList.getLength(); + Vector v = new Vector(size); + for (int i = 0; i < size; i++) + { + v.add(getCMNode(nodeList.item(i)); + } + return v; + } + */ + + public class AvailableContentCMVisitor extends CMVisitor + { + public Hashtable childNodeTable = new Hashtable(); + public Hashtable attributeTable = new Hashtable(); + public Element rootElement; + public CMElementDeclaration rootElementDeclaration; + public boolean isRootVisited; + protected boolean includeSequenceGroups; + + public AvailableContentCMVisitor(Element rootElement, CMElementDeclaration rootElementDeclaration) + { + this.rootElement = rootElement; + this.rootElementDeclaration = rootElementDeclaration; + } + + protected String getKey(CMNode cmNode) + { + String key = cmNode.getNodeName(); + CMDocument cmDocument = (CMDocument)cmNode.getProperty("CMDocument"); + if (cmDocument != null) + { + String namespaceURI = (String)cmDocument.getProperty("http://org.eclipse.wst/cm/properties/targetNamespaceURI"); + if (namespaceURI != null) + { + key = "[" + namespaceURI + "]" + key; + } + } + return key; + } + + public List computeAvailableContent(int includeOptions) + { + Vector v = new Vector(); + + int contentType = rootElementDeclaration.getContentType(); + includeSequenceGroups = ((includeOptions & INCLUDE_SEQUENCE_GROUPS) != 0); + visitCMNode(rootElementDeclaration); + + if ((includeOptions & INCLUDE_ATTRIBUTES) != 0) + { + v.addAll(attributeTable.values()); + CMAttributeDeclaration nillableAttribute = (CMAttributeDeclaration)rootElementDeclaration.getProperty("http://org.eclipse.wst/cm/properties/nillable"); + if (nillableAttribute != null) + { + v.add(nillableAttribute); + } + } + + if ((includeOptions & INCLUDE_CHILD_NODES) != 0) + { + if (contentType == CMElementDeclaration.MIXED || + contentType == CMElementDeclaration.ELEMENT) + { + v.addAll(childNodeTable.values()); + } + else if (contentType == CMElementDeclaration.ANY) + { + CMDocument cmDocument = (CMDocument)rootElementDeclaration.getProperty("CMDocument"); + if (cmDocument != null) + { + CMNamedNodeMap elements = cmDocument.getElements(); + for (Iterator i = elements.iterator(); i.hasNext(); ) + { + v.add(i.next()); + } + } + } + + if (contentType == CMElementDeclaration.MIXED || + contentType == CMElementDeclaration.PCDATA || + contentType == CMElementDeclaration.ANY) + { + CMDataType dataType = rootElementDeclaration.getDataType(); + if (dataType != null) + { + v.add(dataType); + } + } + } + return v; + } + + public void visitCMAnyElement(CMAnyElement anyElement) + { + String uri = anyElement.getNamespaceURI(); + List list = getCMDocumentList(rootElement, rootElementDeclaration, uri); + for (Iterator iterator = list.iterator(); iterator.hasNext(); ) + { + CMDocument cmdocument = (CMDocument)iterator.next(); + if (cmdocument != null) + { + CMNamedNodeMap map = cmdocument.getElements(); + int size = map.getLength(); + for (int i = 0; i < size; i++) + { + CMNode ed = map.item(i); + + childNodeTable.put(getKey(ed), ed); + } + } + } + } + + public void visitCMAttributeDeclaration(CMAttributeDeclaration ad) + { + super.visitCMAttributeDeclaration(ad); + attributeTable.put(ad.getNodeName(), ad); + } + + public void visitCMElementDeclaration(CMElementDeclaration ed) + { + if (ed == rootElementDeclaration && !isRootVisited) + { + isRootVisited = true; + super.visitCMElementDeclaration(ed); + } + else + { + if (!Boolean.TRUE.equals(ed.getProperty("Abstract"))) + { + childNodeTable.put(getKey(ed), ed); + } + + CMNodeList substitutionGroup = (CMNodeList)ed.getProperty("SubstitutionGroup"); + if (substitutionGroup != null) + { + handleSubstitutionGroup(substitutionGroup); + } + } + } + + protected void handleSubstitutionGroup(CMNodeList substitutionGroup) + { + int substitutionGroupLength = substitutionGroup.getLength(); + if (substitutionGroupLength > 1) + { + for (int i = 0; i < substitutionGroupLength; i++) + { + CMNode ed = substitutionGroup.item(i); + if (!Boolean.TRUE.equals(ed.getProperty("Abstract"))) + { + childNodeTable.put(getKey(ed), ed); + } + } + } + } + + public void visitCMGroup(CMGroup group) + { + if (includeSequenceGroups) + { + if (group.getOperator() == CMGroup.SEQUENCE && + group.getChildNodes().getLength() > 1 && + includesRequiredContent(group)) + { + childNodeTable.put(group, group); + } + } + super.visitCMGroup(group); + } + + public boolean includesRequiredContent(CMGroup group) + { + List list = getValidator().createContentSpecificationList(group); + return list.size() > 1; + } + } + + + /** + * @deprected - use getPossibleDataTypeValues() + */ + public List getDataTypeValues(Element element, CMNode cmNode) + { + return Arrays.asList(getPossibleDataTypeValues(element, cmNode)); + } + + /** + * This methods return an array of possible values corresponding to the datatype of the CMNode (either an CMAttributeDeclaration or a CMElementDeclaration) + */ + public String[] getPossibleDataTypeValues(Element element, CMNode cmNode) + { + List list = new Vector(); + + if (cmNode != null) + { + CMDataType dataType = null; + if (cmNode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) + { + dataType = ((CMAttributeDeclaration)cmNode).getAttrType(); + } + else if (cmNode.getNodeType() == CMNode.ELEMENT_DECLARATION) + { + dataType = ((CMElementDeclaration)cmNode).getDataType(); + } + + String[] enumeratedValues = dataType != null ? dataType.getEnumeratedValues() : null; + if (enumeratedValues != null) + { + for (int i = 0; i < enumeratedValues.length; i++) + { + list.add(enumeratedValues[i]); + } + } + } + + addValuesForXSIType(element, cmNode, list); + + if (extensionManager != null) + { + list.addAll(extensionManager.getDataTypeValues(element, cmNode)); + } + + int listSize = list.size(); + String[] result = new String[listSize]; + for (int i = 0; i < listSize; i++) + { + result[i] = (String)list.get(i); + } + return result; + } + + + protected void addValuesForXSIType(Element element, CMNode cmNode, List list) + { + if (cmNode != null && cmNode.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) + { + CMAttributeDeclaration ad = (CMAttributeDeclaration)cmNode; + if (valueHelper.isXSIType(ad)) + { + NamespaceTable table = new NamespaceTable(element.getOwnerDocument()); + table.addElementLineage(element); + list.addAll(valueHelper.getQualifiedXSITypes(ad, table)); + } + } + } + + + public ModelQueryExtensionManager getExtensionManager() + { + return extensionManager; + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java new file mode 100644 index 0000000000..b8b653cc92 --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/SimpleAssociationProvider.java @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument; +import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.ModelQueryCMProvider; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * + */ +public class SimpleAssociationProvider extends BaseAssociationProvider +{ + protected ModelQueryCMProvider modelQueryCMProvider; + + public SimpleAssociationProvider(ModelQueryCMProvider modelQueryCMProvider) + { + this.modelQueryCMProvider = modelQueryCMProvider; + } + + public CMDocument getCorrespondingCMDocument(Node node) + { + return modelQueryCMProvider.getCorrespondingCMDocument(node); + } + + public CMElementDeclaration getCMElementDeclaration(Element element) + { + CMElementDeclaration result = null; + CMDocument cmDocument = getCorrespondingCMDocument(element); + if (cmDocument != null) + { + result = (CMElementDeclaration)cmDocument.getElements().getNamedItem(element.getNodeName()); + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java new file mode 100644 index 0000000000..3313dfaa7d --- /dev/null +++ b/bundles/org.eclipse.wst.sse.core/src-contentmodel/org/eclipse/wst/sse/core/internal/contentmodel/modelqueryimpl/XMLAssociationProvider.java @@ -0,0 +1,402 @@ +/* +* Copyright (c) 2002 IBM Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Common Public License v1.0 +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/cpl-v10.html +* +* Contributors: +* IBM - Initial API and implementation +* Jens Lukowski/Innoopract - initial renaming/restructuring +* +*/ +package org.eclipse.wst.sse.core.internal.contentmodel.modelqueryimpl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.sse.core.internal.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMDocument; +import org.eclipse.wst.sse.core.internal.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.internal.contentmodel.CMNode; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.sse.core.internal.contentmodel.modelquery.CMDocumentReferenceProvider; +import org.eclipse.wst.sse.core.internal.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.internal.contentmodel.util.DOMNamespaceHelper; +import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.sse.core.internal.contentmodel.util.NamespaceTable; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * + */ +public abstract class XMLAssociationProvider extends BaseAssociationProvider implements CMDocumentReferenceProvider +{ + protected CMDocumentCache cmDocumentCache; + protected CMDocumentManagerImpl documentManager; + + public XMLAssociationProvider(CMDocumentCache cmDocumentCache) + { + this.cmDocumentCache = cmDocumentCache; + documentManager = new CMDocumentManagerImpl(cmDocumentCache, this); + } + + public CMDocumentManager getCMDocumentManager() + { + return documentManager; + } + + + public static String[] getDoctypeInfo(Document document) + { + String[] result = null; + DocumentType doctype = document.getDoctype(); + + // defect 206833 ... here we test for DTDs that are declared inline + // since we currently have no way of making use of inline DTDs we ingore them + // so that the implict DTD (if any) can be used + if (doctype != null && (doctype.getPublicId() != null || doctype.getSystemId() != null)) + { + result = new String[2]; + result[0] = doctype.getPublicId(); + result[1] = doctype.getSystemId(); + } + else if (getImplictDoctype(document) != null) + { + result = getImplictDoctype(document); + } + return result; + } + + + protected static String[] getImplictDoctype(Document document) + { + String[] result = null; + /* + DOMExtension domExtension = DOMExtensionProviderRegistry.getInstance().getDOMExtension(document); + if (domExtension != null) + { + result = domExtension.getImplicitDoctype(); + }*/ + return result; + } + + public CMDocument getCorrespondingCMDocument(Node node) + { + return getCorrespondingCMDocument(node, true); + } + + protected CMDocument getCorrespondingCMDocument(Node node, boolean getDocumentFromCMNode) + { + CMDocument result = null; + try + { + Document document = node.getNodeType() == Node.DOCUMENT_NODE ? (Document)node : node.getOwnerDocument(); + + String[] doctypeInfo = getDoctypeInfo(document); + + if (doctypeInfo != null) + { + result = getCMDocument(doctypeInfo[0], doctypeInfo[1], "DTD"); + } + // defect 211236 ... in some cases calling this method can result in a cycle + // we use the getDocumentFromCMNode as a flag to avoid this + // TODO... see if there is a way to re-organize to avoid the need for this flag + else if (getDocumentFromCMNode) + { + CMNode cmNode = getCMNode(node); + if (cmNode != null) + { + // todo... add a getCMDocument() methods to CMNode + // for now use the getProperty interface + result = (CMDocument)cmNode.getProperty("CMDocument"); + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + return result; + } + + + public CMDocument getCMDocument(Element element, String uri) + { + CMDocument result = null; + NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument()); + namespaceTable.addElementLineage(element); + NamespaceInfo namespaceInfo = namespaceTable.getNamespaceInfoForURI(uri); + if (namespaceInfo != null) + { + result = getCMDocument(namespaceInfo.uri, namespaceInfo.locationHint, "XSD"); + } + return result; + } + + + public CMDocument getCMDocument(String publicId, String systemId, String type) + { + //String resolvedGrammarURI = resolveGrammarURI(document, publicId, systemId); + return documentManager.getCMDocument(publicId, systemId, type); + } + + //public CMDocument getCMDocument(Document document, String publicId, String systemId) + //{ + // //String resolvedGrammarURI = resolveGrammarURI(document, publicId, systemId); + // return documentManager.getCMDocument(publicId, systemId); + //} + + public String resolveGrammarURI(String publicId, String systemId) + { + return resolveGrammarURI(null, publicId, systemId); + } + + + /** + * This method should be specialized in order to implement specialized uri resolution + */ + protected String resolveGrammarURI(Document document, String publicId, String systemId) + { + return systemId; + } + + + public CMElementDeclaration getCMElementDeclaration(Element element) + { + CMElementDeclaration result = null; + Document document = element.getOwnerDocument(); + String[] doctypeInfo = getDoctypeInfo(document); + if (doctypeInfo != null) + { + // we have detected doctype information so we assume that we can locate the CMElementDeclaration + // in the CMDocument's table of global elements + CMDocument cmDocument = getCorrespondingCMDocument(element, false); + + // TODO... consider replacing above with + // CMDocument cmDocument = getCMDocument(document, doctypeInfo[0], doctypeInfo[1]); + + if (cmDocument != null) + { + result = (CMElementDeclaration)cmDocument.getElements().getNamedItem(element.getNodeName()); + + // this is a hack to get our xsl code assist working... we might want to handle similar + // grammar behaviour via some established model query setting + if (result == null && getImplictDoctype(document) != null) + { + Node parent = element.getParentNode(); + if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) + { + result = getCMElementDeclaration((Element)parent); + } + } + } + } + else + { + // here we use a namespaceTable to consider if the root element has any namespace information + // + NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument()); + List list = NamespaceTable.getElementLineage(element); + Element rootElement = (Element)list.get(0); + namespaceTable.addElement(rootElement); + + if (namespaceTable.isNamespaceEncountered()) + { + // we assume that this is an XMLSchema style namespace aware document + result = getCMElementDeclaration(element, list, namespaceTable); + } + else + { + // we assume that this is an inferred CMDocument for a DTD style 'namespaceless' document + CMDocument cmDocument = getCMDocument("", "", "DTD"); + if (cmDocument != null) + { + result = (CMElementDeclaration)cmDocument.getElements().getNamedItem(element.getNodeName()); + } + } + } + return result; + } + + + protected CMElementDeclaration getCMElementDeclaration(Element targetElement, List list, NamespaceTable namespaceTable) + { + CMElementDeclaration currentED = null; + try + { + int listSize = list.size(); + for (int i = 0; i < listSize; i++) + { + Element element = (Element)list.get(i); + + if (i != 0) + { + namespaceTable.addElement(element); + } + + String nodeName = element.getNodeName(); + String unprefixedName = DOMNamespaceHelper.getUnprefixedName(nodeName); + String prefix = DOMNamespaceHelper.getPrefix(nodeName); + + CMElementDeclaration ed = null; + + // see if the element is a local of the currentED + // + if (currentED != null) + { + ed = (CMElementDeclaration)currentED.getLocalElements().getNamedItem(unprefixedName); + } + + if (ed == null) + { + NamespaceInfo namespaceInfo = namespaceTable.getNamespaceInfoForPrefix(prefix); + if (namespaceInfo != null) + { + CMDocument cmDocument = getCMDocument(namespaceInfo.uri, namespaceInfo.locationHint, "XSD"); + if (cmDocument != null) + { + ed = (CMElementDeclaration)cmDocument.getElements().getNamedItem(unprefixedName); + } + } + } + currentED = ed; + + // handle XSIType + if (currentED != null) + { + CMElementDeclaration derivedED = getDerivedCMElementDeclaration(element, currentED, namespaceTable); + if (derivedED != null) + { + currentED = derivedED; + } + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + return currentED; + } + + + protected CMElementDeclaration getDerivedCMElementDeclaration(Element element, CMElementDeclaration ed, NamespaceTable namespaceTable) + { + CMElementDeclaration result = null; + String xsiPrefix = namespaceTable.getPrefixForURI("http://www.w3.org/2001/XMLSchema-instance"); + if (xsiPrefix != null) + { + String xsiTypeValue = element.getAttribute(xsiPrefix + ":type"); + if (xsiTypeValue != null) + { + String typePrefix = DOMNamespaceHelper.getPrefix(xsiTypeValue); + String typeName = DOMNamespaceHelper.getUnprefixedName(xsiTypeValue); + String typeURI = namespaceTable.getURIForPrefix(typePrefix); + String uriQualifiedTypeName = typeName; + if (typeURI != null && typeURI.length() > 0) + { + uriQualifiedTypeName = "[" + typeURI + "]" + typeName; + } + result = (CMElementDeclaration)ed.getProperty("DerivedElementDeclaration=" + uriQualifiedTypeName); + } + } + return result; + } + + + public CMAttributeDeclaration getCMAttributeDeclaration(Attr attr) + { + CMAttributeDeclaration result = null; + Element element = attr.getOwnerElement(); + if (element != null) + { + CMElementDeclaration ed = getCMElementDeclaration(element); + if (ed != null) + { + result = (CMAttributeDeclaration)ed.getAttributes().getNamedItem(attr.getName()); + if (result == null) + { + // try to get the unprefixed name + String name = DOMNamespaceHelper.getUnprefixedName(attr.getName()); + result = (CMAttributeDeclaration)ed.getAttributes().getNamedItem(name); + } + if (result == null) + { + // todo... perhaps this is a globally defined attribute... + } + } + } + return result; + } + + /** + * This method returns a list of CMDocumentReferences associated with a particular node or subtree + */ + public List getCMDocumentReferences(Node node, boolean deep) + { + List result = new ArrayList(); + Document document = (node.getNodeType() == Node.DOCUMENT_NODE) ? (Document)node : node.getOwnerDocument(); + DocumentType doctype = document.getDoctype(); + // defect 206833 ... here we test for DTDs that are declared inline + // since we currently have no way of making use of inline DTDs we ingore them + // so that the implict DTD (if any) can be used + if (doctype != null && (doctype.getPublicId() != null || doctype.getSystemId() != null)) + { + String uri = resolveGrammarURI(document, doctype.getPublicId(), doctype.getSystemId()); + result.add(new CMDocumentReferenceImpl(doctype.getPublicId(), uri)); + } + else if (getImplictDoctype(document) != null) + { + String[] implicitDoctype = getImplictDoctype(document); + String uri = resolveGrammarURI(document, implicitDoctype[0], implicitDoctype[1]); + result.add(new CMDocumentReferenceImpl(implicitDoctype[0], uri)); + } + else + { + NamespaceTable namespaceTable = new NamespaceTable(document); + if (node.getNodeType() == Node.ELEMENT_NODE) + { + namespaceTable.addElement((Element)node); + } + if (deep) + { + addChildElementsToNamespaceTable(node, namespaceTable); + } + List list = namespaceTable.getNamespaceInfoList(); + for (Iterator i = list.iterator(); i.hasNext();) + { + NamespaceInfo info = (NamespaceInfo) i.next(); + String uri = resolveGrammarURI(document, info.uri, info.locationHint); + result.add(new CMDocumentReferenceImpl(info.uri, uri)); + } + } + return result; + } + + protected void addChildElementsToNamespaceTable(Node node, NamespaceTable namespaceTable) + { + NodeList nodeList = node.getChildNodes(); + if (nodeList != null) + { + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) + { + Node childNode = nodeList.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) + { + namespaceTable.addElement((Element)childNode); + addChildElementsToNamespaceTable(childNode, namespaceTable); + } + } + } + } +} |