Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal')
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java81
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java274
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java19
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java107
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java30
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java44
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java99
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java156
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java1222
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java22
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java756
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java140
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java42
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java353
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java183
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java74
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java1073
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java120
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java222
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java1421
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java227
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java89
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java55
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java514
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java809
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java257
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java111
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java138
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java227
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java630
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java334
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java351
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java143
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java605
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java29
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java548
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java167
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java1107
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java738
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java237
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java875
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java469
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java2365
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java1647
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java39
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java40
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java46
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java386
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java97
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java49
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java541
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java21
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java595
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java125
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java42
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java1699
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java92
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java170
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java167
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java36
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java105
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java36
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java205
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java95
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java98
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java98
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java190
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java179
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java179
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java25
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java111
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java86
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java113
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java168
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java36
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java104
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java45
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java51
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java50
79 files changed, 25229 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java
new file mode 100644
index 0000000000..4275c5047d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal;
+
+import java.util.ArrayList;
+
+import org.eclipse.wst.sse.core.AbstractAdapterFactory;
+import org.eclipse.wst.sse.core.AdapterFactory;
+import org.eclipse.wst.sse.core.INodeAdapter;
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.PropagatingAdapterFactory;
+
+
+public class DebugAdapterFactory extends AbstractAdapterFactory implements PropagatingAdapterFactory {
+
+ /**
+ * Constructor for PageDirectiveWatcherFactory.
+ */
+ public DebugAdapterFactory() {
+ this(IDebugAdapter.class, true);
+ }
+
+ /**
+ * Constructor for PageDirectiveWatcherFactory.
+ *
+ * @param adapterKey
+ * @param registerAdapters
+ */
+ public DebugAdapterFactory(Object adapterKey, boolean registerAdapters) {
+ super(adapterKey, registerAdapters);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.PropagatingAdapterFactory#addContributedFactories(org.eclipse.wst.sse.core.AdapterFactory)
+ */
+ public void addContributedFactories(AdapterFactory factory) {
+ //none expected
+ }
+
+ public AdapterFactory copy() {
+ return new DebugAdapterFactory(this.adapterKey, this.shouldRegisterAdapter);
+ }
+
+ protected INodeAdapter createAdapter(INodeNotifier target) {
+ EveryNodeDebugAdapter result = null;
+ result = EveryNodeDebugAdapter.getInstance();
+ return result;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.AdapterFactory#isFactoryForType(java.lang.Object)
+ */
+ public boolean isFactoryForType(Object type) {
+
+ return IDebugAdapter.class == type;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.PropagatingAdapterFactory#setContributedFactories(java.util.ArrayList)
+ */
+ public void setContributedFactories(ArrayList list) {
+ // none expected
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java
new file mode 100644
index 0000000000..dc238974fc
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal;
+
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.wst.sse.core.IModelStateListener;
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.IStructuredModel;
+import org.eclipse.wst.sse.core.events.AboutToBeChangeEvent;
+import org.eclipse.wst.sse.core.events.IModelAboutToBeChangedListener;
+import org.eclipse.wst.sse.core.events.IStructuredDocumentListener;
+import org.eclipse.wst.sse.core.events.NewDocumentEvent;
+import org.eclipse.wst.sse.core.events.NoChangeEvent;
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.RegionsReplacedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentRegionsReplacedEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.xml.core.document.XMLNode;
+
+
+/**
+ * Purely for use in debugging
+ */
+public class EveryNodeDebugAdapter implements IDebugAdapter {
+
+ static class InternalDocumentListener implements IDocumentListener {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
+ */
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ Debug.println("IdocumentAboutToBeChanged: " + event); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
+ */
+ public void documentChanged(DocumentEvent event) {
+ Debug.println("IdocumentChanged: " + event); //$NON-NLS-1$
+
+ }
+
+ }
+
+ static class InternalModelStateListener implements IModelStateListener {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.IModelStateListener#modelAboutToBeChanged(org.eclipse.wst.sse.core.IStructuredModel)
+ */
+ public void modelAboutToBeChanged(IStructuredModel model) {
+ Debug.println("modelAboutToBeChanged: " + model); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.IModelStateListener#modelChanged(org.eclipse.wst.sse.core.IStructuredModel)
+ */
+ public void modelChanged(IStructuredModel model) {
+ Debug.println("modelChanged: " + model); //$NON-NLS-1$
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.IModelStateListener#modelDirtyStateChanged(org.eclipse.wst.sse.core.IStructuredModel,
+ * boolean)
+ */
+ public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) {
+ Debug.println("modelDirtyStateChanged: " + model); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.IModelStateListener#modelResourceDeleted(org.eclipse.wst.sse.core.IStructuredModel)
+ */
+ public void modelResourceDeleted(IStructuredModel model) {
+ Debug.println("modelResourceDeleted: " + model); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.IModelStateListener#modelResourceMoved(org.eclipse.wst.sse.core.IStructuredModel,
+ * org.eclipse.wst.sse.core.IStructuredModel)
+ */
+ public void modelResourceMoved(IStructuredModel oldModel, IStructuredModel newModel) {
+ Debug.println("modelResourceMoved: " + "oldModel: " + oldModel + "newModel: " + newModel); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ }
+
+ static class InternalStructuredDocumentAboutToChange implements IModelAboutToBeChangedListener {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.events.IModelAboutToBeChangedListener#modelAboutToBeChanged(org.eclipse.wst.sse.core.events.AboutToBeChangeEvent)
+ */
+ public void modelAboutToBeChanged(AboutToBeChangeEvent structuredDocumentEvent) {
+ Debug.println("structuredDocumentAboutToBeChanged: " + structuredDocumentEvent); //$NON-NLS-1$
+
+ }
+
+ }
+
+ static class InternalStructuredDocumentListener implements IStructuredDocumentListener {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#newModel(org.eclipse.wst.sse.core.events.NewDocumentContentEvent)
+ */
+ public void newModel(NewDocumentEvent structuredDocumentEvent) {
+ Debug.println("structuredDocumentChanged - newModel: " + structuredDocumentEvent); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#noChange(org.eclipse.wst.sse.core.events.NoChangeEvent)
+ */
+ public void noChange(NoChangeEvent structuredDocumentEvent) {
+ Debug.println("structuredDocumentChanged - noChange: " + structuredDocumentEvent); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#nodesReplaced(org.eclipse.wst.sse.core.events.StructuredDocumentRegionsReplacedEvent)
+ */
+ public void nodesReplaced(StructuredDocumentRegionsReplacedEvent structuredDocumentEvent) {
+ Debug.println("structuredDocumentChanged - nodesReplaced: " + structuredDocumentEvent); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#regionChanged(org.eclipse.wst.sse.core.events.RegionChangedEvent)
+ */
+ public void regionChanged(RegionChangedEvent structuredDocumentEvent) {
+ Debug.println("structuredDocumentChanged - regionChanged: " + structuredDocumentEvent); //$NON-NLS-1$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#regionsReplaced(org.eclipse.wst.sse.core.events.RegionsReplacedEvent)
+ */
+ public void regionsReplaced(RegionsReplacedEvent structuredDocumentEvent) {
+ Debug.println("structuredDocumentChanged - regionsReplaced: " + structuredDocumentEvent); //$NON-NLS-1$
+
+ }
+
+ }
+
+ private static EveryNodeDebugAdapter singletonInstance;
+
+ public static EveryNodeDebugAdapter getInstance() {
+ if (singletonInstance == null) {
+ singletonInstance = new EveryNodeDebugAdapter();
+ }
+ return singletonInstance;
+ }
+
+ InternalDocumentListener fInternalDocumentListener;
+ InternalModelStateListener fInternalModelStateListener;
+ InternalStructuredDocumentAboutToChange fInternalStructuredDocumentAboutToChange;
+ InternalStructuredDocumentListener fInternalStructuredDocumentListener;
+ IStructuredModel fModel;
+
+ /**
+ *
+ */
+ public EveryNodeDebugAdapter() {
+ super();
+ fInternalDocumentListener = new InternalDocumentListener();
+ fInternalStructuredDocumentAboutToChange = new InternalStructuredDocumentAboutToChange();
+ fInternalStructuredDocumentListener = new InternalStructuredDocumentListener();
+ fInternalModelStateListener = new InternalModelStateListener();
+ }
+
+ /**
+ * @param target
+ */
+ public EveryNodeDebugAdapter(INodeNotifier target) {
+ this();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.INodeAdapter#isAdapterForType(java.lang.Object)
+ */
+ public boolean isAdapterForType(Object type) {
+ return (type == IDebugAdapter.class);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.INodeAdapter#notifyChanged(org.eclipse.wst.sse.core.INodeNotifier,
+ * int, java.lang.Object, java.lang.Object, java.lang.Object, int)
+ */
+ public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ if (notifier instanceof XMLNode) {
+ setModel(((XMLNode) notifier).getModel());
+ }
+ Debug.println("notifier: " + notifier + " " + INodeNotifier.EVENT_TYPE_STRINGS[eventType] + " changedFeature: " + changedFeature + " oldValue: " + oldValue + " newValue: " + newValue + " pos: " + pos); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.internal.IDebugAdapter#setDocument(org.eclipse.wst.sse.core.text.IStructuredDocument)
+ */
+ private void setModel(IStructuredModel structuredModel) {
+ if (fModel == structuredModel)
+ return;
+
+ if (fModel != null) {
+ fModel.removeModelStateListener(fInternalModelStateListener);
+ //
+ IStructuredDocument structuredDocument = fModel.getStructuredDocument();
+ if (structuredDocument != null) {
+ structuredDocument.removeDocumentListener(fInternalDocumentListener);
+ structuredDocument.removeDocumentAboutToChangeListener(fInternalStructuredDocumentAboutToChange);
+ structuredDocument.removeDocumentChangedListener(fInternalStructuredDocumentListener);
+ }
+ }
+ fModel = structuredModel;
+ if (fModel != null) {
+
+ fModel.addModelStateListener(fInternalModelStateListener);
+ //
+ IStructuredDocument structuredDocument = fModel.getStructuredDocument();
+ if (structuredDocument != null) {
+ structuredDocument.addDocumentListener(fInternalDocumentListener);
+ structuredDocument.addDocumentAboutToChangeListener(fInternalStructuredDocumentAboutToChange);
+ structuredDocument.addDocumentChangedListener(fInternalStructuredDocumentListener);
+ }
+ }
+
+
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java
new file mode 100644
index 0000000000..50b902514e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal;
+
+import org.eclipse.wst.sse.core.INodeAdapter;
+
+
+public interface IDebugAdapter extends INodeAdapter {
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java
new file mode 100644
index 0000000000..e5f04fa496
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * This is an "adapter" class, simply to get in input stream to act like a
+ * reader. We could not use InputStreamReader directly because its internal
+ * buffers are not controllable, and it sometimes pulls too much out of input
+ * stream (even when it wasn't needed for our purposes).
+ *
+ * The use of this class is highly specialized and by not means meant to be
+ * general purpose. Its use is restricted to those cases where the input
+ * stream can be regarded as ascii just long enough to determine what the real
+ * encoding should be.
+ */
+
+public class ByteReader extends Reader {
+
+ /** Default byte buffer size (2048). */
+ public static final int DEFAULT_BUFFER_SIZE = 2048;
+
+ protected byte[] fBuffer;
+
+ protected InputStream fInputStream;
+
+ protected ByteReader() {
+ super();
+ }
+
+ public ByteReader(InputStream inputStream) {
+ this(inputStream, DEFAULT_BUFFER_SIZE);
+ if (!inputStream.markSupported()) {
+ throw new IllegalArgumentException("ByteReader is required to have a resettable stream"); //$NON-NLS-1$
+ }
+ }
+
+ public ByteReader(InputStream inputStream, int size) {
+ fInputStream = inputStream;
+ if (!inputStream.markSupported()) {
+ throw new IllegalArgumentException("ByteReader is required to have a resettable stream"); //$NON-NLS-1$
+ }
+ fBuffer = new byte[size];
+
+ }
+
+ public void close() throws IOException {
+ fInputStream.close();
+ }
+
+ public void mark(int readAheadLimit) throws IOException {
+ fInputStream.mark(readAheadLimit);
+ }
+
+ public boolean markSupported() {
+ return true;
+ }
+
+ public int read() throws IOException {
+ int b0 = fInputStream.read();
+ return (b0 & 0x00FF);
+ }
+
+ public int read(char ch[], int offset, int length) throws IOException {
+ if (length > fBuffer.length) {
+ length = fBuffer.length;
+ }
+
+ int count = fInputStream.read(fBuffer, 0, length);
+
+ for (int i = 0; i < count; i++) {
+ int b0 = fBuffer[i];
+ // the 0x00FF is to "lose" the negative bits filled in the byte to
+ // int conversion
+ // (and which would be there if cast directly from byte to char).
+ char c0 = (char) (b0 & 0x00FF);
+ ch[i] = c0;
+ }
+ return count;
+ }
+
+ public boolean ready() throws IOException {
+ return fInputStream.available() > 0;
+ }
+
+ public void reset() throws IOException {
+ fInputStream.reset();
+ }
+
+ public long skip(long n) throws IOException {
+ return fInputStream.skip(n);
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java
new file mode 100644
index 0000000000..7e12f93503
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+
+public interface EncodingParserConstants {
+
+ final String EOF = "EOF"; //$NON-NLS-1$
+ final String InvalidTerminatedStringValue = "InvalidTerminatedStringValue"; //$NON-NLS-1$
+ final String InvalidTermintatedUnDelimitedStringValue = "InvalidTermintatedUnDelimitedStringValue"; //$NON-NLS-1$
+ final String MAX_CHARS_REACHED = "MAX_CHARS_REACHED"; //$NON-NLS-1$
+ final String StringValue = "strval"; //$NON-NLS-1$
+ final String UnDelimitedStringValue = "UnDelimitedStringValue"; //$NON-NLS-1$
+ String UTF16BE = "UTF16BE"; //$NON-NLS-1$
+ String UTF16LE = "UTF16LE"; //$NON-NLS-1$
+
+
+ String UTF83ByteBOM = "UTF83ByteBOM"; //$NON-NLS-1$
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java
new file mode 100644
index 0000000000..0f14b8b570
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+public class HeadParserToken {
+ private int fStart;
+
+ private String fText;
+ private String fType;
+
+ protected HeadParserToken() {
+ super();
+ }
+
+ public HeadParserToken(String type, int start, String text) {
+ this();
+ fType = type;
+ fStart = start;
+ fText = text;
+
+ }
+
+ public String getText() {
+ return fText;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return ("text: " + fText + " offset: " + fStart + " type: " + fType); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java
new file mode 100644
index 0000000000..1d1052d850
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+/*
+ *
+ * A non-resizable class implementing the behavior of java.util.Stack, but
+ * directly for the <code> integer </code> primitive.
+ */
+import java.util.EmptyStackException;
+
+public class IntStack {
+ private int[] list = null;
+
+ private int size = 0;
+
+ public IntStack() {
+ this(100);
+ }
+
+ public IntStack(int maxdepth) {
+ super();
+ list = new int[maxdepth];
+ initialize();
+ }
+
+ public void clear() {
+ initialize();
+ }
+
+ public boolean empty() {
+ return size == 0;
+ }
+
+ public int get(int slot) {
+ return list[slot];
+ }
+
+ private void initialize() {
+ for (int i = 0; i < list.length; i++)
+ list[i] = -1;
+ }
+
+ /**
+ * Returns the int at the top of the stack without removing it
+ *
+ * @return int at the top of this stack.
+ * @exception EmptyStackException
+ * when empty.
+ */
+ public int peek() {
+ if (size == 0)
+ throw new EmptyStackException();
+ return list[size - 1];
+ }
+
+ /**
+ * Removes and returns the int at the top of the stack
+ *
+ * @return int at the top of this stack.
+ * @exception EmptyStackException
+ * when empty.
+ */
+ public int pop() {
+ int value = peek();
+ list[size - 1] = -1;
+ size--;
+ return value;
+ }
+
+ /**
+ * Pushes an item onto the top of this stack.
+ *
+ * @param newValue -
+ * the int to be pushed onto this stack.
+ * @return the <code>newValue</code> argument.
+ */
+ public int push(int newValue) {
+ if (size == list.length) {
+ throw new StackOverflowError();
+ }
+ list[size++] = newValue;
+ return newValue;
+ }
+
+ public int size() {
+ return list.length;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java
new file mode 100644
index 0000000000..5843f61c4f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+
+public class XMLDeclDetector {
+ private static final int MAX_BUF_SIZE = 1024 * 2;
+ private static final int MAX_MARK_SIZE = 1024 * 2;
+ protected boolean fHeaderParsed;
+ private boolean fIsXML;
+ protected Reader fReader;
+ //private boolean DEBUG = false;
+ private XMLHeadTokenizer fTokenizer;
+
+ private boolean canHandleAsUnicodeStream(String tokenType) {
+ boolean canHandleAsUnicodeStream = false;
+ if (tokenType == EncodingParserConstants.UTF83ByteBOM) {
+ canHandleAsUnicodeStream = true;
+ //fUnicode = "UTF-8"; //$NON-NLS-1$
+ } else if (tokenType == EncodingParserConstants.UTF16BE) {
+ canHandleAsUnicodeStream = true;
+ //fUnicode = "UTF-16BE"; //$NON-NLS-1$
+ } else if (tokenType == EncodingParserConstants.UTF16LE) {
+ canHandleAsUnicodeStream = true;
+ //fUnicode = "UTF-16"; //$NON-NLS-1$
+ }
+ return canHandleAsUnicodeStream;
+ }
+
+ final private void ensureInputSet() {
+ if (fReader == null) {
+ throw new IllegalStateException("input must be set before use"); //$NON-NLS-1$
+ }
+ }
+
+ //private String fUnicode;
+
+ /**
+ * @return Returns the tokenizer.
+ */
+ private XMLHeadTokenizer getTokenizer() {
+ if (fTokenizer == null) {
+ fTokenizer = new XMLHeadTokenizer();
+ }
+ return fTokenizer;
+ }
+
+ /**
+ * @return Returns the isXML.
+ */
+ public boolean isXML() throws IOException {
+ ensureInputSet();
+ if (!fHeaderParsed) {
+ parseInput();
+ }
+ return fIsXML;
+ }
+
+ private void parseInput() throws IOException {
+ XMLHeadTokenizer tokenizer = getTokenizer();
+ tokenizer.reset(fReader);
+ HeadParserToken token = null;
+ String tokenType = null;
+ do {
+ token = tokenizer.getNextToken();
+ tokenType = token.getType();
+ if (canHandleAsUnicodeStream(tokenType)) {
+ fReader.reset();
+ // this is (obviously) not always true.
+ // TODO: need to fix so we "remember" original iFile or
+ // inputstream, and
+ // create appropriate InputStreamReader.
+ // I'm not sure what to do for the set(reader) case ... if its
+ // even relevent.
+ // plus, ensure against infinite loops!
+ fIsXML = true;
+ //fReader = new InputStreamReader(fReader, fUnicode);
+ // parseInput();
+ } else {
+ if (tokenType == XMLHeadTokenizerConstants.XMLDelEncoding) {
+ fIsXML = true;
+ }
+ }
+ } while (tokenizer.hasMoreTokens());
+
+ }
+
+ private void resetAll() {
+ fReader = null;
+ fHeaderParsed = false;
+ fIsXML = false;
+ //fUnicode = null;
+
+ }
+
+ public void set(IFile iFile) throws CoreException {
+ resetAll();
+ InputStream inputStream = iFile.getContents(true);
+ InputStream resettableStream = new BufferedInputStream(inputStream, MAX_BUF_SIZE);
+ resettableStream.mark(MAX_MARK_SIZE);
+ set(resettableStream);
+ }
+
+ public void set(InputStream inputStream) {
+ resetAll();
+ fReader = new ByteReader(inputStream);
+ try {
+ fReader.mark(MAX_MARK_SIZE);
+ } catch (IOException e) {
+ // impossible, since we know ByteReader supports marking
+ throw new Error(e);
+ }
+ }
+
+ /**
+ * Note: this is not part of interface to help avoid confusion ... it
+ * expected this Reader is a well formed character reader ... that is, its
+ * all ready been determined to not be a unicode marked input stream. And,
+ * its assumed to be in the correct position, at position zero, ready to
+ * read first character.
+ */
+ public void set(Reader reader) {
+ resetAll();
+ fReader = reader;
+ if (!fReader.markSupported()) {
+ fReader = new BufferedReader(fReader);
+ }
+
+ try {
+ fReader.mark(MAX_MARK_SIZE);
+ } catch (IOException e) {
+ // impossble, since we just checked if markable
+ throw new Error(e);
+ }
+
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java
new file mode 100644
index 0000000000..b4a9b6ebba
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java
@@ -0,0 +1,1222 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+/* The following code was generated by JFlex 1.2.2 on 4/6/04 11:13 PM */
+
+/*nlsXXX*/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+import java.io.IOException;
+import java.io.Reader;
+
+
+
+/**
+ * This class is a scanner generated by <a
+ * href="http://www.informatik.tu-muenchen.de/~kleing/jflex/">JFlex </a> 1.2.2
+ * on 4/6/04 11:13 PM from the specification file
+ * <tt>file:/D:/DevTimeSupport/HeadParsers/XMLHeadTokenizer/XMLHeadTokenizer.jflex</tt>
+ */
+public class XMLHeadTokenizer {
+
+ /** this character denotes the end of file */
+ final public static int YYEOF = -1;
+
+ /** lexical states */
+ final public static int YYINITIAL = 0;
+ final public static int UnDelimitedString = 10;
+ final public static int DQ_STRING = 6;
+ final public static int SQ_STRING = 8;
+ final public static int ST_XMLDecl = 2;
+ final public static int QuotedAttributeValue = 4;
+
+ /**
+ * YY_LEXSTATE[l] is the state in the DFA for the lexical state l
+ * YY_LEXSTATE[l+1] is the state in the DFA for the lexical state l at the
+ * beginning of a line l is of the form l = 2*k, k a non negative integer
+ */
+ private final static int YY_LEXSTATE[] = {0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6};
+
+ /**
+ * Translates characters to character classes
+ */
+ final private static String yycmap_packed = "\11\0\1\6\1\7\2\0\1\11\22\0\1\6\1\0\1\27\2\0" + "\1\31\1\0\1\30\24\0\1\12\1\10\1\26\1\13\3\0\1\21" + "\1\23\1\17\1\0\1\25\1\0\1\24\2\0\1\16\1\15\1\20" + "\1\22\10\0\1\14\12\0\1\21\1\23\1\17\1\0\1\25\1\0" + "\1\24\2\0\1\16\1\15\1\20\1\22\10\0\1\14\102\0\1\4" + "\3\0\1\5\17\0\1\3\16\0\1\1\20\0\1\3\16\0\1\1" + "\1\2\170\0\1\2\ufe87\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ final private static char[] yycmap = yy_unpack_cmap(yycmap_packed);
+
+
+ /* error codes */
+ final private static int YY_UNKNOWN_ERROR = 0;
+ final private static int YY_ILLEGAL_STATE = 1;
+ final private static int YY_NO_MATCH = 2;
+ final private static int YY_PUSHBACK_2BIG = 3;
+
+ /* error messages for the codes above */
+ final private static String YY_ERROR_MSG[] = {"Unkown internal scanner error", "Internal error: unknown state", "Error: could not match input", "Error: pushback value was too large"};
+
+ /** the input device */
+ private java.io.Reader yy_reader;
+
+ /** the current state of the DFA */
+ private int yy_state;
+
+ /** the current lexical state */
+ private int yy_lexical_state = YYINITIAL;
+
+ /**
+ * this buffer contains the current text to be matched and is the source
+ * of the yytext() string
+ */
+ private char yy_buffer[] = new char[16384];
+
+ /** the textposition at the last accepting state */
+ private int yy_markedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int yy_pushbackPos;
+
+ /** the current text position in the buffer */
+ private int yy_currentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int yy_startRead;
+
+ /**
+ * endRead marks the last character in the buffer, that has been read from
+ * input
+ */
+ private int yy_endRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ private int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ int yycolumn;
+
+ /**
+ * yy_atBOL == true <=>the scanner is currently at the beginning of a line
+ */
+ private boolean yy_atBOL;
+
+ /** yy_atEOF == true <=>the scanner has returned a value for EOF */
+ private boolean yy_atEOF;
+
+ /** denotes if the user-EOF-code has already been executed */
+ private boolean yy_eof_done;
+
+ /* user code: */
+
+
+ private boolean hasMore = true;
+ private final static int MAX_TO_SCAN = 1000;
+ StringBuffer string = new StringBuffer();
+ // state stack for easier state handling
+ private IntStack fStateStack = new IntStack();
+ private String valueText = null;
+
+
+ public XMLHeadTokenizer() {
+ super();
+ }
+
+ public void reset(Reader in) {
+ /* the input device */
+ yy_reader = in;
+
+ /* the current state of the DFA */
+ yy_state = 0;
+
+ /* the current lexical state */
+ yy_lexical_state = YYINITIAL;
+
+ /*
+ * this buffer contains the current text to be matched and is the
+ * source of the yytext() string
+ */
+ java.util.Arrays.fill(yy_buffer, (char) 0);
+
+ /* the textposition at the last accepting state */
+ yy_markedPos = 0;
+
+ /* the textposition at the last state to be included in yytext */
+ yy_pushbackPos = 0;
+
+ /* the current text position in the buffer */
+ yy_currentPos = 0;
+
+ /* startRead marks the beginning of the yytext() string in the buffer */
+ yy_startRead = 0;
+
+ /**
+ * endRead marks the last character in the buffer, that has been read
+ * from input
+ */
+ yy_endRead = 0;
+
+ /* number of newlines encountered up to the start of the matched text */
+ yyline = 0;
+
+ /* the number of characters up to the start of the matched text */
+ yychar = 0;
+
+ /**
+ * the number of characters from the last newline up to the start of
+ * the matched text
+ */
+ yycolumn = 0;
+
+ /**
+ * yy_atBOL == true <=>the scanner is currently at the beginning of a
+ * line
+ */
+ yy_atBOL = false;
+
+ /* yy_atEOF == true <=> the scanner has returned a value for EOF */
+ yy_atEOF = false;
+
+ /* denotes if the user-EOF-code has already been executed */
+ yy_eof_done = false;
+
+
+ fStateStack.clear();
+
+ hasMore = true;
+
+ // its a little wasteful to "throw away" first char array generated
+ // by class init (via auto generated code), but we really do want
+ // a small buffer for our head parsers.
+ if (yy_buffer.length != MAX_TO_SCAN) {
+ yy_buffer = new char[MAX_TO_SCAN];
+ }
+
+
+ }
+
+
+ public final HeadParserToken getNextToken() throws IOException {
+ String context = null;
+ context = primGetNextToken();
+ HeadParserToken result = null;
+ if (valueText != null) {
+ result = createToken(context, yychar, valueText);
+ valueText = null;
+ } else {
+ result = createToken(context, yychar, yytext());
+ }
+ return result;
+ }
+
+ public final boolean hasMoreTokens() {
+ return hasMore && yychar < MAX_TO_SCAN;
+ }
+
+ private void pushCurrentState() {
+ fStateStack.push(yystate());
+
+ }
+
+ private void popState() {
+ yybegin(fStateStack.pop());
+ }
+
+ private HeadParserToken createToken(String context, int start, String text) {
+ return new HeadParserToken(context, start, text);
+ }
+
+
+
+ /**
+ * Creates a new scanner There is also a java.io.InputStream version of
+ * this constructor.
+ *
+ * @param in
+ * the java.io.Reader to read input from.
+ */
+ public XMLHeadTokenizer(java.io.Reader in) {
+ this.yy_reader = in;
+ }
+
+ /**
+ * Creates a new scanner. There is also java.io.Reader version of this
+ * constructor.
+ *
+ * @param in
+ * the java.io.Inputstream to read input from.
+ */
+ public XMLHeadTokenizer(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed
+ * the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char[] yy_unpack_cmap(String packed) {
+ char[] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 128) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do
+ map[j++] = value;
+ while (--count > 0);
+ }
+ return map;
+ }
+
+
+ /**
+ * Gets the next input character.
+ *
+ * @return the next character of the input stream, EOF if the end of the
+ * stream is reached.
+ * @exception IOException
+ * if any I/O-Error occurs
+ */
+ private int yy_advance() throws java.io.IOException {
+
+ /* standard case */
+ if (yy_currentPos < yy_endRead)
+ return yy_buffer[yy_currentPos++];
+
+ /* if the eof is reached, we don't need to work hard */
+ if (yy_atEOF)
+ return YYEOF;
+
+ /* otherwise: need to refill the buffer */
+
+ /* first: make room (if you can) */
+ if (yy_startRead > 0) {
+ System.arraycopy(yy_buffer, yy_startRead, yy_buffer, 0, yy_endRead - yy_startRead);
+
+ /* translate stored positions */
+ yy_endRead -= yy_startRead;
+ yy_currentPos -= yy_startRead;
+ yy_markedPos -= yy_startRead;
+ yy_pushbackPos -= yy_startRead;
+ yy_startRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (yy_currentPos >= yy_buffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[yy_currentPos * 2];
+ System.arraycopy(yy_buffer, 0, newBuffer, 0, yy_buffer.length);
+ yy_buffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = yy_reader.read(yy_buffer, yy_endRead, yy_buffer.length - yy_endRead);
+
+ if (numRead == -1)
+ return YYEOF;
+
+ yy_endRead += numRead;
+
+ return yy_buffer[yy_currentPos++];
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ final public void yyclose() throws java.io.IOException {
+ yy_atEOF = true; /* indicate end of file */
+ yy_endRead = yy_startRead; /* invalidate buffer */
+ yy_reader.close();
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ final public int yystate() {
+ return yy_lexical_state;
+ }
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState
+ * the new lexical state
+ */
+ final public void yybegin(int newState) {
+ yy_lexical_state = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ final public String yytext() {
+ return new String(yy_buffer, yy_startRead, yy_markedPos - yy_startRead);
+ }
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ final public int yylength() {
+ return yy_markedPos - yy_startRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * @param errorCode
+ * the code of the errormessage to display
+ */
+ private void yy_ScanError(int errorCode) {
+ try {
+ System.out.println(YY_ERROR_MSG[errorCode]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println(YY_ERROR_MSG[YY_UNKNOWN_ERROR]);
+ }
+
+ // System.exit(1);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number
+ * the number of characters to be read again. This number must
+ * not be greater than yylength()!
+ */
+ private void yypushback(int number) {
+ if (number > yylength())
+ yy_ScanError(YY_PUSHBACK_2BIG);
+
+ yy_markedPos -= number;
+ }
+
+
+ /**
+ * Contains user EOF-code, which will be executed exactly once, when the
+ * end of file is reached
+ */
+ private void yy_do_eof() {
+ if (!yy_eof_done) {
+ yy_eof_done = true;
+ hasMore = false;
+
+ }
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched, the end
+ * of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception IOException
+ * if any I/O-Error occurs
+ */
+ public String primGetNextToken() throws java.io.IOException {
+ int yy_input;
+ int yy_action;
+
+
+ while (true) {
+
+ yychar += yylength();
+
+ yy_atBOL = yy_markedPos <= 0 || yy_buffer[yy_markedPos - 1] == '\n';
+ if (!yy_atBOL && yy_buffer[yy_markedPos - 1] == '\r') {
+ yy_atBOL = yy_advance() != '\n';
+ if (!yy_atEOF)
+ yy_currentPos--;
+ }
+
+ yy_action = -1;
+
+ yy_currentPos = yy_startRead = yy_markedPos;
+
+ if (yy_atBOL)
+ yy_state = YY_LEXSTATE[yy_lexical_state + 1];
+ else
+ yy_state = YY_LEXSTATE[yy_lexical_state];
+
+
+ yy_forAction : {
+ while (true) {
+
+ yy_input = yy_advance();
+
+ if (yy_input == YYEOF)
+ break yy_forAction;
+
+ yy_input = yycmap[yy_input];
+
+ boolean yy_isFinal = false;
+ boolean yy_noLookAhead = false;
+
+ yy_forNext : {
+ switch (yy_state) {
+ case 0 :
+ switch (yy_input) {
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 7;
+ break yy_forNext;
+ }
+
+ case 1 :
+ switch (yy_input) {
+ case 1 :
+ yy_isFinal = true;
+ yy_state = 8;
+ break yy_forNext;
+ case 2 :
+ yy_isFinal = true;
+ yy_state = 9;
+ break yy_forNext;
+ case 3 :
+ yy_isFinal = true;
+ yy_state = 10;
+ break yy_forNext;
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 11;
+ break yy_forNext;
+ case 10 :
+ yy_isFinal = true;
+ yy_state = 12;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 7;
+ break yy_forNext;
+ }
+
+ case 2 :
+ switch (yy_input) {
+ case 11 :
+ yy_isFinal = true;
+ yy_state = 13;
+ break yy_forNext;
+ case 15 :
+ yy_isFinal = true;
+ yy_state = 14;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 7;
+ break yy_forNext;
+ }
+
+ case 3 :
+ switch (yy_input) {
+ case 6 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 16;
+ break yy_forNext;
+ case 7 :
+ yy_isFinal = true;
+ yy_state = 17;
+ break yy_forNext;
+ case 23 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 18;
+ break yy_forNext;
+ case 24 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 19;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 15;
+ break yy_forNext;
+ }
+
+ case 4 :
+ switch (yy_input) {
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 21;
+ break yy_forNext;
+ case 11 :
+ yy_isFinal = true;
+ yy_state = 22;
+ break yy_forNext;
+ case 23 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 23;
+ break yy_forNext;
+ case 24 :
+ yy_isFinal = true;
+ yy_state = 24;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 20;
+ break yy_forNext;
+ }
+
+ case 5 :
+ switch (yy_input) {
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 21;
+ break yy_forNext;
+ case 24 :
+ yy_isFinal = true;
+ yy_state = 25;
+ break yy_forNext;
+ case 25 :
+ yy_isFinal = true;
+ yy_state = 26;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 20;
+ break yy_forNext;
+ }
+
+ case 6 :
+ switch (yy_input) {
+ case 11 :
+ yy_isFinal = true;
+ yy_state = 26;
+ break yy_forNext;
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 27;
+ break yy_forNext;
+ case 23 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 28;
+ break yy_forNext;
+ case 24 :
+ yy_isFinal = true;
+ yy_state = 29;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 20;
+ break yy_forNext;
+ }
+
+ case 8 :
+ switch (yy_input) {
+ case 2 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 30;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 9 :
+ switch (yy_input) {
+ case 1 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 31;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 10 :
+ switch (yy_input) {
+ case 4 :
+ yy_state = 32;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 11 :
+ switch (yy_input) {
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_state = 33;
+ break yy_forNext;
+ case 10 :
+ yy_state = 34;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 12 :
+ switch (yy_input) {
+ case 11 :
+ yy_state = 35;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 13 :
+ switch (yy_input) {
+ case 22 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 36;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 14 :
+ switch (yy_input) {
+ case 16 :
+ yy_state = 37;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 16 :
+ switch (yy_input) {
+ case 6 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 16;
+ break yy_forNext;
+ case 7 :
+ yy_state = 38;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 15;
+ break yy_forNext;
+ }
+
+ case 17 :
+ switch (yy_input) {
+ case 6 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 16;
+ break yy_forNext;
+ case 7 :
+ yy_state = 38;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 15;
+ break yy_forNext;
+ }
+
+ case 22 :
+ switch (yy_input) {
+ case 22 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 39;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 24 :
+ switch (yy_input) {
+ case 10 :
+ yy_state = 40;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 25 :
+ switch (yy_input) {
+ case 10 :
+ yy_state = 40;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 26 :
+ switch (yy_input) {
+ case 22 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 41;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 29 :
+ switch (yy_input) {
+ case 10 :
+ yy_state = 40;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 32 :
+ switch (yy_input) {
+ case 5 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 42;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 33 :
+ switch (yy_input) {
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_state = 33;
+ break yy_forNext;
+ case 10 :
+ yy_state = 34;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 34 :
+ switch (yy_input) {
+ case 11 :
+ yy_state = 35;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 35 :
+ switch (yy_input) {
+ case 12 :
+ yy_state = 43;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 37 :
+ switch (yy_input) {
+ case 17 :
+ yy_state = 44;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 38 :
+ switch (yy_input) {
+ case 6 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 16;
+ break yy_forNext;
+ case 7 :
+ yy_state = 38;
+ break yy_forNext;
+ default :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 15;
+ break yy_forNext;
+ }
+
+ case 40 :
+ switch (yy_input) {
+ case 24 :
+ yy_isFinal = true;
+ yy_noLookAhead = true;
+ yy_state = 21;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 43 :
+ switch (yy_input) {
+ case 13 :
+ yy_state = 45;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 44 :
+ switch (yy_input) {
+ case 18 :
+ yy_state = 46;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 45 :
+ switch (yy_input) {
+ case 14 :
+ yy_state = 47;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 46 :
+ switch (yy_input) {
+ case 19 :
+ yy_state = 48;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 47 :
+ switch (yy_input) {
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 49;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 48 :
+ switch (yy_input) {
+ case 20 :
+ yy_state = 50;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 49 :
+ switch (yy_input) {
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 49;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 50 :
+ switch (yy_input) {
+ case 16 :
+ yy_state = 51;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 51 :
+ switch (yy_input) {
+ case 21 :
+ yy_state = 52;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 52 :
+ switch (yy_input) {
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_state = 52;
+ break yy_forNext;
+ case 8 :
+ yy_isFinal = true;
+ yy_state = 53;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ case 53 :
+ switch (yy_input) {
+ case 6 :
+ case 7 :
+ case 9 :
+ yy_isFinal = true;
+ yy_state = 53;
+ break yy_forNext;
+ default :
+ break yy_forAction;
+ }
+
+ default :
+ yy_ScanError(YY_ILLEGAL_STATE);
+ break;
+ }
+ }
+
+ if (yy_isFinal) {
+ yy_action = yy_state;
+ yy_markedPos = yy_currentPos;
+ if (yy_noLookAhead)
+ break yy_forAction;
+ }
+
+ }
+ }
+
+
+ switch (yy_action) {
+
+ case 25 : {
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.StringValue;
+ }
+ case 55 :
+ break;
+ case 21 : {
+ yypushback(1);
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.InvalidTerminatedStringValue;
+ }
+ case 56 :
+ break;
+ case 15 :
+ case 16 : {
+ yypushback(1);
+ yybegin(UnDelimitedString);
+ string.setLength(0);
+ }
+ case 57 :
+ break;
+ case 28 :
+ case 29 : {
+ yypushback(1);
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.InvalidTermintatedUnDelimitedStringValue;
+ }
+ case 58 :
+ break;
+ case 39 : {
+ yypushback(2);
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.InvalidTerminatedStringValue;
+ }
+ case 59 :
+ break;
+ case 41 : {
+ yypushback(2);
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.InvalidTerminatedStringValue;
+ }
+ case 60 :
+ break;
+ case 7 :
+ case 8 :
+ case 9 :
+ case 10 :
+ case 11 :
+ case 12 :
+ case 13 :
+ case 14 :
+ case 17 : {
+ if (yychar > MAX_TO_SCAN) {
+ hasMore = false;
+ return EncodingParserConstants.MAX_CHARS_REACHED;
+ }
+ }
+ case 61 :
+ break;
+ case 30 : {
+ if (yychar == 0) {
+ hasMore = false;
+ return EncodingParserConstants.UTF16BE;
+ }
+ }
+ case 62 :
+ break;
+ case 31 : {
+ if (yychar == 0) {
+ hasMore = false;
+ return EncodingParserConstants.UTF16LE;
+ }
+ }
+ case 63 :
+ break;
+ case 42 : {
+ if (yychar == 0) {
+ hasMore = false;
+ return EncodingParserConstants.UTF83ByteBOM;
+ }
+ }
+ case 64 :
+ break;
+ case 49 : {
+ if (yychar == 0) {
+ yybegin(ST_XMLDecl);
+ return XMLHeadTokenizerConstants.XMLDeclStart;
+ }
+ }
+ case 65 :
+ break;
+ case 36 : {
+ yybegin(YYINITIAL);
+ hasMore = false;
+ return XMLHeadTokenizerConstants.XMLDeclEnd;
+ }
+ case 66 :
+ break;
+ case 53 : {
+ pushCurrentState();
+ yybegin(QuotedAttributeValue);
+ return XMLHeadTokenizerConstants.XMLDelEncoding;
+ }
+ case 67 :
+ break;
+ case 23 : {
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.StringValue;
+ }
+ case 68 :
+ break;
+ case 20 :
+ case 22 :
+ case 24 :
+ case 26 : {
+ string.append(yytext());
+ }
+ case 69 :
+ break;
+ case 19 : {
+ yybegin(SQ_STRING);
+ string.setLength(0);
+ }
+ case 70 :
+ break;
+ case 18 : {
+ yybegin(DQ_STRING);
+ string.setLength(0);
+ }
+ case 71 :
+ break;
+ case 27 : {
+ yypushback(1);
+ popState();
+ valueText = string.toString();
+ return EncodingParserConstants.UnDelimitedStringValue;
+ }
+ case 72 :
+ break;
+ default :
+ if (yy_input == YYEOF && yy_startRead == yy_currentPos) {
+ yy_atEOF = true;
+ yy_do_eof();
+ {
+ hasMore = false;
+ return EncodingParserConstants.EOF;
+ }
+ } else {
+ yy_ScanError(YY_NO_MATCH);
+ }
+ }
+ }
+ }
+
+ /**
+ * Runs the scanner on input files.
+ *
+ * This main method is the debugging routine for the scanner. It prints
+ * each returned token to System.out until the end of file is reached, or
+ * an error occured.
+ *
+ * @param argv
+ * the command line, contains the filenames to run the scanner
+ * on.
+ */
+ public static void main(String argv[]) {
+ for (int i = 0; i < argv.length; i++) {
+ XMLHeadTokenizer scanner = null;
+ try {
+ scanner = new XMLHeadTokenizer(new java.io.FileReader(argv[i]));
+ } catch (java.io.FileNotFoundException e) {
+ System.out.println("File not found : \"" + argv[i] + "\"");
+ System.exit(1);
+ }
+ // catch (java.io.IOException e) {
+ // System.out.println("Error opening file \"" + argv[i] + "\"");
+ // System.exit(1);
+ // }
+ catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println("Usage : java XMLHeadTokenizer <inputfile>");
+ System.exit(1);
+ }
+
+ try {
+ do {
+ System.out.println(scanner.primGetNextToken());
+ } while (!scanner.yy_atEOF);
+
+ } catch (java.io.IOException e) {
+ System.out.println("An I/O error occured while scanning :");
+ System.out.println(e);
+ System.exit(1);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ }
+
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java
new file mode 100644
index 0000000000..3321348059
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.contenttype;
+
+
+public interface XMLHeadTokenizerConstants extends EncodingParserConstants {
+
+ final String XMLDeclEnd = "XMLDeclEnd"; //$NON-NLS-1$
+ final String XMLDeclStart = "XMLDeclStart"; //$NON-NLS-1$
+ final String XMLDelEncoding = "XMLDelEncoding"; //$NON-NLS-1$
+ // final String XMLDeclVersion = "XMLDeclVersion";
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java
new file mode 100644
index 0000000000..959f512544
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java
@@ -0,0 +1,756 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.common.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.document.XMLAttr;
+import org.eclipse.wst.xml.core.document.XMLCharEntity;
+import org.eclipse.wst.xml.core.document.XMLNamespace;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ * AttrImpl class
+ */
+public class AttrImpl extends NodeImpl implements XMLAttr {
+ private ITextRegion equalRegion = null;
+
+ private String name = null;
+ private ITextRegion nameRegion = null;
+ private String namespaceURI = null;
+ private ElementImpl ownerElement = null;
+ private ITextRegion valueRegion = null;
+ private String valueSource = null;
+
+ /**
+ * AttrImpl constructor
+ */
+ protected AttrImpl() {
+ super();
+ }
+
+ /**
+ * AttrImpl constructor
+ *
+ * @param that
+ * AttrImpl
+ */
+ protected AttrImpl(AttrImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.name = that.name;
+ this.valueSource = that.getValueSource();
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node cloneNode(boolean deep) {
+ AttrImpl cloned = new AttrImpl(this);
+ return cloned;
+ }
+
+ /**
+ */
+ protected CMAttributeDeclaration getDeclaration() {
+ ElementImpl element = (ElementImpl) getOwnerElement();
+ if (element == null)
+ return null;
+ CMElementDeclaration elementDecl = element.getDeclaration();
+ if (elementDecl == null)
+ return null;
+ CMNamedNodeMap attributes = elementDecl.getAttributes();
+ if (attributes == null)
+ return null;
+ return (CMAttributeDeclaration) attributes.getNamedItem(getName());
+ }
+
+ /**
+ * getEndOffset method
+ *
+ * @return int
+ */
+ public int getEndOffset() {
+ if (this.ownerElement == null)
+ return 0;
+ int offset = this.ownerElement.getStartOffset();
+ if (this.valueRegion != null) {
+ return (offset + this.valueRegion.getEnd());
+ }
+ if (this.equalRegion != null) {
+ return (offset + this.equalRegion.getEnd());
+ }
+ if (this.nameRegion != null) {
+ return (offset + this.nameRegion.getEnd());
+ }
+ return 0;
+ }
+
+ /**
+ * getEqualRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.ITextRegion
+ */
+ public ITextRegion getEqualRegion() {
+ return this.equalRegion;
+ }
+
+ /**
+ */
+ public String getLocalName() {
+ if (this.name == null)
+ return null;
+ int index = this.name.indexOf(':');
+ if (index < 0)
+ return this.name;
+ return this.name.substring(index + 1);
+ }
+
+ /**
+ * getName method
+ *
+ * @return java.lang.String
+ */
+ public String getName() {
+ if (this.name == null)
+ return new String();
+ return this.name;
+ }
+
+ /**
+ * getNameRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.ITextRegion
+ */
+ public ITextRegion getNameRegion() {
+ return this.nameRegion;
+ }
+
+ public int getNameRegionEndOffset() {
+ if (this.ownerElement == null)
+ return 0;
+ // assuming the firstStructuredDocumentRegion is the one that contains
+ // attributes
+ IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return 0;
+ return flatNode.getEndOffset(this.nameRegion);
+ }
+
+ public int getNameRegionStartOffset() {
+ if (this.ownerElement == null)
+ return 0;
+ // assuming the firstStructuredDocumentRegion is the one that contains
+ // attributes
+ IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return 0;
+ return flatNode.getStartOffset(this.nameRegion);
+ }
+
+ public String getNameRegionText() {
+ if (this.ownerElement == null)
+ return null;
+ // assuming the firstStructuredDocumentRegion is the one that contains
+ // attributes
+ IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return null;
+ return flatNode.getText(this.nameRegion);
+ }
+
+ public int getNameRegionTextEndOffset() {
+ if (this.ownerElement == null)
+ return 0;
+ // assuming the firstStructuredDocumentRegion is the one that contains
+ // attributes
+ IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return 0;
+ return flatNode.getTextEndOffset(this.nameRegion);
+ }
+
+ /**
+ */
+ public String getNamespaceURI() {
+ String nsAttrName = null;
+ String prefix = getPrefix();
+ if (prefix != null && prefix.length() > 0) {
+ if (prefix.equals(XMLNamespace.XMLNS)) {
+ // fixed URI
+ return XMLNamespace.XMLNS_URI;
+ }
+ nsAttrName = XMLNamespace.XMLNS_PREFIX + prefix;
+ } else {
+ String name = getName();
+ if (name != null && name.equals(XMLNamespace.XMLNS)) {
+ // fixed URI
+ return XMLNamespace.XMLNS_URI;
+ }
+ // does not inherit namespace from owner element
+ // if (this.ownerElement != null) return
+ // this.ownerElement.getNamespaceURI();
+ return this.namespaceURI;
+ }
+
+ for (Node node = this.ownerElement; node != null; node = node.getParentNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ break;
+ Element element = (Element) node;
+ Attr attr = element.getAttributeNode(nsAttrName);
+ if (attr != null)
+ return attr.getValue();
+ }
+
+ return this.namespaceURI;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return getName();
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return ATTRIBUTE_NODE;
+ }
+
+ /**
+ * getNodeValue method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeValue() {
+ return getValue();
+ }
+
+ /**
+ * getOwnerElement method
+ *
+ * @return org.w3c.dom.Element
+ */
+ public Element getOwnerElement() {
+ return this.ownerElement;
+ }
+
+ /**
+ */
+ public String getPrefix() {
+ if (this.name == null)
+ return null;
+ int index = this.name.indexOf(':');
+ if (index <= 0)
+ return null;
+ // exclude JSP tag in name
+ if (this.name.charAt(0) == '<')
+ return null;
+ return this.name.substring(0, index);
+ }
+
+ /**
+ * getSpecified method
+ *
+ * @return boolean
+ */
+ public boolean getSpecified() {
+ return true;
+ }
+
+ /**
+ * getStartOffset method
+ *
+ * @return int
+ */
+ public int getStartOffset() {
+ if (this.ownerElement == null)
+ return 0;
+ int offset = this.ownerElement.getStartOffset();
+ if (this.nameRegion != null) {
+ return (offset + this.nameRegion.getStart());
+ }
+ if (this.equalRegion != null) {
+ return (offset + this.equalRegion.getStart());
+ }
+ if (this.valueRegion != null) {
+ return (offset + this.valueRegion.getStart());
+ }
+ return 0;
+ }
+
+ /**
+ * getValue method
+ *
+ * @return java.lang.String
+ */
+ public String getValue() {
+ return getValue(getValueSource());
+ }
+
+ /**
+ * Returns value for the source
+ */
+ private String getValue(String source) {
+ if (source == null)
+ return new String();
+ if (source.length() == 0)
+ return source;
+ StringBuffer buffer = null;
+ int offset = 0;
+ int length = source.length();
+ int ref = source.indexOf('&');
+ while (ref >= 0) {
+ int end = source.indexOf(';', ref + 1);
+ if (end > ref + 1) {
+ String name = source.substring(ref + 1, end);
+ String value = getCharValue(name);
+ if (value != null) {
+ if (buffer == null)
+ buffer = new StringBuffer(length);
+ if (ref > offset)
+ buffer.append(source.substring(offset, ref));
+ buffer.append(value);
+ offset = end + 1;
+ ref = end;
+ }
+ }
+ ref = source.indexOf('&', ref + 1);
+ }
+ if (buffer == null)
+ return source;
+ if (length > offset)
+ buffer.append(source.substring(offset));
+ return buffer.toString();
+ }
+
+ /**
+ * getValueRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.ITextRegion
+ */
+ public ITextRegion getValueRegion() {
+ return this.valueRegion;
+ }
+
+ public int getValueRegionStartOffset() {
+ if (this.ownerElement == null)
+ return 0;
+ // assuming the firstStructuredDocumentRegion is the one that contains
+ // attributes
+ IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return 0;
+ return flatNode.getStartOffset(this.valueRegion);
+ }
+
+ public String getValueRegionText() {
+ if (this.ownerElement == null)
+ return null;
+ // assuming the firstStructuredDocumentRegion is the one that contains
+ // attributes
+ IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return null;
+ if (this.valueRegion == null)
+ return null;
+ return flatNode.getText(this.valueRegion);
+ }
+
+ /**
+ */
+ public String getValueSource() {
+ if (this.valueSource != null)
+ return this.valueSource;
+ // DW: 4/16/2003 due to change in structuredDocument ... we need a
+ // flatnode to
+ // get at region values. For now I'll assume this is always the first
+ // flatnode .. may need to make smarter later (e.g. to search for
+ // the flatnode that this.valueRegion belongs to.
+ // DW: 4/30/2003 For some reason, this method is getting called a lot
+ // Not sure if its a threading problem, or a fundamental error
+ // elsewhere.
+ // It needs more investigation, but in the use cases I've seen,
+ // doesn't
+ // seem to hurt to simply return null in those cases. I saw this null
+ // case,
+ // when tryint go format an XML file.
+ if (this.ownerElement == null)
+ return null;
+ IStructuredDocumentRegion ownerRegion = this.ownerElement.getFirstStructuredDocumentRegion();
+ if (ownerRegion == null)
+ return null;
+ if (this.valueRegion != null)
+ return StructuredDocumentRegionUtil.getAttrValue(ownerRegion, this.valueRegion);
+ return new String();
+ }
+
+ private String getValueSource(ElementImpl ownerElement) {
+ if (this.valueSource != null)
+ return this.valueSource;
+ // DW: 4/16/2003 due to change in structuredDocument ... we need a
+ // flatnode to
+ // get at region values. For now I'll assume this is always the first
+ // flatnode .. may need to make smarter later (e.g. to search for
+ // the flatnode that this.valueRegion belongs to.
+ if (this.valueRegion != null)
+ return StructuredDocumentRegionUtil.getAttrValue(ownerElement.getStructuredDocumentRegion(), this.valueRegion);
+ return new String();
+ }
+
+ /**
+ */
+ private String getValueSource(String value) {
+ if (value == null)
+ return null;
+ if (value.length() == 0)
+ return value;
+ StringBuffer buffer = null;
+ int offset = 0;
+ int length = value.length();
+ int amp = value.indexOf('&');
+ while (amp >= 0) {
+ if (buffer == null)
+ buffer = new StringBuffer(length + 4);
+ if (amp > offset)
+ buffer.append(value.substring(offset, amp));
+ buffer.append(XMLCharEntity.AMP_REF);
+ offset = amp + 1;
+ amp = value.indexOf('&', offset);
+ }
+ if (buffer == null)
+ return value;
+ if (length > offset)
+ buffer.append(value.substring(offset));
+ return buffer.toString();
+ }
+
+ /**
+ * Check if Attr has JSP in value
+ */
+ public boolean hasJSPValue() {
+ if (this.valueRegion == null)
+ return false;
+ if (!(this.valueRegion instanceof ITextRegionContainer))
+ return false;
+ ITextRegionList regions = ((ITextRegionContainer) this.valueRegion).getRegions();
+ if (regions == null)
+ return false;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ if (region == null)
+ continue;
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_OPEN || regionType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN || regionType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN || regionType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if Attr has only name but not equal sign nor value
+ */
+ public boolean hasNameOnly() {
+ return (this.nameRegion != null && this.equalRegion == null && this.valueRegion == null);
+ }
+
+ /**
+ */
+ protected final boolean hasPrefix() {
+ if (this.name == null)
+ return false;
+ if (this.name.indexOf(':') <= 0)
+ return false;
+ // exclude JSP tag in name
+ if (this.name.charAt(0) == '<')
+ return false;
+ return true;
+ }
+
+ /**
+ */
+ protected final boolean ignoreCase() {
+ if (this.ownerElement != null) {
+ if (this.ownerElement.ignoreCase()) {
+ return !hasPrefix();
+ }
+ } else {
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document != null && document.ignoreCase()) {
+ // even in case insensitive document, if having prefix, it's
+ // case sensitive
+ return !hasPrefix();
+ }
+ }
+ return false;
+ }
+
+ /**
+ */
+ public boolean isGlobalAttr() {
+ if (hasPrefix())
+ return false;
+ if (this.ownerElement == null)
+ return false;
+ return this.ownerElement.isGlobalTag();
+ }
+
+ /**
+ */
+ public final boolean isXMLAttr() {
+ if (this.ownerElement != null) {
+ if (!this.ownerElement.isXMLTag()) {
+ return hasPrefix();
+ }
+ } else {
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document != null && !document.isXMLType()) {
+ // even in non-XML document, if having prefix, it's XML tag
+ return hasPrefix();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * matchName method
+ *
+ * @return boolean
+ * @param name
+ * java.lang.String
+ */
+ protected boolean matchName(String name) {
+ if (name == null)
+ return (this.name == null);
+ if (this.name == null)
+ return false;
+ if (!ignoreCase())
+ return this.name.equals(name);
+ return this.name.equalsIgnoreCase(name);
+ }
+
+ /**
+ * notifyValueChanged method
+ */
+ protected void notifyNameChanged() {
+ if (this.ownerElement == null)
+ return;
+ DocumentImpl document = (DocumentImpl) this.ownerElement.getContainerDocument();
+ if (document == null)
+ return;
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.nameChanged(this);
+ }
+
+ /**
+ * notifyValueChanged method
+ */
+ protected void notifyValueChanged() {
+ if (this.ownerElement == null)
+ return;
+ DocumentImpl document = (DocumentImpl) this.ownerElement.getContainerDocument();
+ if (document == null)
+ return;
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.valueChanged(this);
+ }
+
+ /**
+ * removeRegions method
+ */
+ void removeRegions() {
+ this.nameRegion = null;
+ this.valueRegion = null;
+ this.equalRegion = null;
+ }
+
+ /**
+ */
+ void resetRegions() {
+ this.valueSource = getValueSource();
+ removeRegions();
+ }
+
+ /**
+ */
+ void resetRegions(ElementImpl ownerElement) {
+ this.valueSource = getValueSource(ownerElement);
+ removeRegions();
+ }
+
+ /**
+ * setEqualRegion method
+ *
+ * @param equalRegion
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ void setEqualRegion(ITextRegion equalRegion) {
+ this.equalRegion = equalRegion;
+ }
+
+ /**
+ * setName method
+ *
+ * @param name
+ * java.lang.String
+ */
+ protected void setName(String name) {
+ String value = null;
+ int startOffset = 0;
+ if (this.ownerElement != null) {
+ value = getValue();
+ startOffset = this.ownerElement.getStartOffset();
+ this.ownerElement.notify(CHANGE, this, value, null, startOffset);
+ }
+ this.name = name;
+ if (this.ownerElement != null) {
+ this.ownerElement.notify(CHANGE, this, null, value, startOffset);
+ }
+ }
+
+ /**
+ * setNameRegion method
+ *
+ * @param nameRegion
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ void setNameRegion(ITextRegion nameRegion) {
+ this.nameRegion = nameRegion;
+ }
+
+ /**
+ */
+ protected void setNamespaceURI(String namespaceURI) {
+ this.namespaceURI = namespaceURI;
+ }
+
+ /**
+ * setNodeValue method
+ *
+ * @param nodeValue
+ * java.lang.String
+ */
+ public void setNodeValue(String nodeValue) throws DOMException {
+ setValue(nodeValue);
+ }
+
+ /**
+ * setOwnerElement method
+ *
+ * @param ownerElement
+ * org.w3c.dom.Element
+ */
+ protected void setOwnerElement(Element ownerElement) {
+ this.ownerElement = (ElementImpl) ownerElement;
+ }
+
+ /**
+ */
+ public void setPrefix(String prefix) throws DOMException {
+ if (this.ownerElement != null && !this.ownerElement.isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ int prefixLength = (prefix != null ? prefix.length() : 0);
+ String localName = getLocalName();
+ if (prefixLength == 0) {
+ setName(localName);
+ return;
+ }
+ if (localName == null)
+ localName = new String();
+ int localLength = localName.length();
+ StringBuffer buffer = new StringBuffer(prefixLength + 1 + localLength);
+ buffer.append(prefix);
+ buffer.append(':');
+ buffer.append(localName);
+ setName(buffer.toString());
+
+ notifyNameChanged();
+ }
+
+ /**
+ * setValue method
+ *
+ * @param value
+ * java.lang.String
+ */
+ public void setValue(String value) {
+ // Remember: as we account for "floaters" in
+ // future, remember that some are created
+ // in the natural process of implementing
+ // DOM apis.
+ // this "self notification" of about/changed,
+ // is added for this case, because it known to
+ // be called from properties pages. Should be a
+ // added to all DOM Modifiying APIs eventually.
+ try {
+ getModel().aboutToChangeModel();
+ setValueSource(getValueSource(value));
+ } finally {
+ getModel().changedModel();
+ }
+ }
+
+ /**
+ * setValueRegion method
+ *
+ * @param newValueRegion
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ void setValueRegion(ITextRegion valueRegion) {
+ this.valueRegion = valueRegion;
+ if (valueRegion != null)
+ this.valueSource = null;
+ }
+
+ /**
+ */
+ public void setValueSource(String source) {
+ if (this.ownerElement != null && !this.ownerElement.isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ this.valueSource = source;
+
+ notifyValueChanged();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java
new file mode 100644
index 0000000000..3954ca2d40
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+
+
+/**
+ * CDATASectionImpl class
+ */
+public class CDATASectionImpl extends TextImpl implements CDATASection {
+
+ /**
+ * CDATASectionImpl constructor
+ */
+ protected CDATASectionImpl() {
+ super();
+ }
+
+ /**
+ * CDATASectionImpl constructor
+ *
+ * @param that
+ * CDATASectionImpl
+ */
+ protected CDATASectionImpl(CDATASectionImpl that) {
+ super(that);
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ CDATASectionImpl cloned = new CDATASectionImpl(this);
+ return cloned;
+ }
+
+ /**
+ * getData method
+ *
+ * @return java.lang.String
+ */
+ public String getData() throws DOMException {
+ // instead of super(TextImpl).getData(), call getCharacterData()
+ String data = getCharacterData();
+ if (data == null) {
+ data = getData(getStructuredDocumentRegion());
+ if (data == null)
+ data = new String();
+ }
+ return data;
+ }
+
+ /**
+ */
+ private String getData(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return null;
+
+ ITextRegion contentRegion = null;
+ StringBuffer buffer = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_CDATA_OPEN || regionType == XMLRegionContext.XML_CDATA_CLOSE) {
+ continue;
+ }
+ if (contentRegion == null) { // first content
+ contentRegion = region;
+ } else { // multiple contents
+ if (buffer == null) {
+ buffer = new StringBuffer(flatNode.getText(contentRegion));
+ }
+ buffer.append(flatNode.getText(region));
+ }
+ }
+
+ if (buffer != null)
+ return buffer.toString();
+ if (contentRegion != null)
+ return flatNode.getText(contentRegion);
+ return null;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return "#cdata-section";//$NON-NLS-1$
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return CDATA_SECTION_NODE;
+ }
+
+ /**
+ */
+ public boolean isClosed() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return true; // will be generated
+ String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode);
+ return (regionType == XMLRegionContext.XML_CDATA_CLOSE);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java
new file mode 100644
index 0000000000..44ecfabad5
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+
+
+/**
+ */
+public class CMNodeUtil {
+
+ /**
+ */
+ public static CMAttributeDeclaration getAttributeDeclaration(Attr attr) {
+ if (attr == null)
+ return null;
+ return ((AttrImpl) attr).getDeclaration();
+ }
+
+ /**
+ */
+ public static CMElementDeclaration getElementDeclaration(Element element) {
+ if (element == null)
+ return null;
+ return ((ElementImpl) element).getDeclaration();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java
new file mode 100644
index 0000000000..4c4a2dbc72
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java
@@ -0,0 +1,353 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.w3c.dom.CharacterData;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+
+
+/**
+ * CharacterDataImpl class
+ */
+public abstract class CharacterDataImpl extends NodeImpl implements XMLJSPRegionContexts, CharacterData {
+
+ private String data = null;
+
+ /**
+ * CharacterDataImpl constructor
+ */
+ protected CharacterDataImpl() {
+ super();
+ }
+
+ /**
+ * CharacterDataImpl constructor
+ *
+ * @param that
+ * CharacterDataImpl
+ */
+ protected CharacterDataImpl(CharacterDataImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.data = that.getData();
+ }
+ }
+
+ /**
+ * appendData method
+ *
+ * @param arg
+ * java.lang.String
+ */
+ public void appendData(String arg) throws DOMException {
+ if (arg == null)
+ return;
+
+ String data = getData();
+ if (data == null)
+ data = arg;
+ else
+ data += arg;
+ setData(data);
+ }
+
+ /**
+ * deleteData method
+ *
+ * @param offset
+ * int
+ * @param count
+ * int
+ */
+ public void deleteData(int offset, int count) throws DOMException {
+ if (count == 0)
+ return;
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ if (count < 0 || offset < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String data = getData();
+ if (data == null) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ int length = data.length();
+ if (offset > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ if (offset == 0) {
+ if (count > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ if (count == length)
+ data = new String();
+ else
+ data = data.substring(count);
+ } else {
+ int end = offset + count;
+ if (end > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ if (end == length)
+ data = data.substring(0, offset);
+ else
+ data = data.substring(0, offset) + data.substring(end);
+ }
+ setData(data);
+ }
+
+ /**
+ */
+ protected final String getCharacterData() {
+ return this.data;
+ }
+
+ /**
+ * getData method
+ *
+ * @return java.lang.String
+ */
+ public String getData() throws DOMException {
+ return getCharacterData();
+ }
+
+ /**
+ * getLength method
+ *
+ * @return int
+ */
+ public int getLength() {
+ String data = getData();
+ if (data == null)
+ return 0;
+ return data.length();
+ }
+
+ /**
+ * getNodeValue method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeValue() {
+ return getData();
+ }
+
+ /**
+ * insertData method
+ *
+ * @param offset
+ * int
+ * @param arg
+ * java.lang.String
+ */
+ public void insertData(int offset, String arg) throws DOMException {
+ if (arg == null)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ if (offset < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String data = getData();
+ if (data == null) {
+ if (offset > 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ data = arg;
+ } else if (offset == 0) {
+ data = arg + data;
+ } else {
+ int length = data.length();
+ if (offset > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ if (offset == length)
+ data += arg;
+ else
+ data = data.substring(0, offset) + arg + data.substring(offset);
+ }
+ setData(data);
+ }
+
+ /**
+ * isJSPContent method
+ *
+ * @return boolean
+ */
+ public boolean isJSPContent() {
+ Node parent = getParentNode();
+ if (parent == null || parent.getNodeType() != Node.ELEMENT_NODE)
+ return false;
+ ElementImpl element = (ElementImpl) parent;
+ return element.isJSPContainer();
+ }
+
+ /**
+ * replaceData method
+ *
+ * @param offset
+ * int
+ * @param count
+ * int
+ * @param arg
+ * java.lang.String
+ */
+ public void replaceData(int offset, int count, String arg) throws DOMException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ if (arg == null) {
+ deleteData(offset, count);
+ return;
+ }
+ if (count == 0) {
+ insertData(offset, arg);
+ return;
+ }
+ if (offset < 0 || count < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String data = getData();
+ if (data == null) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ } else if (offset == 0) {
+ int length = data.length();
+ if (count > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ if (count == length)
+ data = arg;
+ else
+ data = arg + data.substring(count);
+ } else {
+ int length = data.length();
+ int end = offset + count;
+ if (end > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ if (end == length)
+ data = data.substring(0, offset) + arg;
+ else
+ data = data.substring(0, offset) + arg + data.substring(end);
+ }
+ setData(data);
+ }
+
+ /**
+ */
+ void resetStructuredDocumentRegions() {
+ this.data = getData();
+ setStructuredDocumentRegion(null);
+ }
+
+ /**
+ * setData method
+ *
+ * @param data
+ * java.lang.String
+ */
+ public void setData(String data) throws DOMException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.data = data;
+
+ notifyValueChanged();
+ }
+
+ /**
+ * setNodeValue method
+ *
+ * @param nodeValue
+ * java.lang.String
+ */
+ public void setNodeValue(String nodeValue) throws DOMException {
+ setData(nodeValue);
+ }
+
+ /**
+ */
+ void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ super.setStructuredDocumentRegion(flatNode);
+ if (flatNode != null)
+ this.data = null;
+ }
+
+ /**
+ * substringData method
+ *
+ * @return java.lang.String
+ * @param offset
+ * int
+ * @param count
+ * int
+ */
+ public String substringData(int offset, int count) throws DOMException {
+ if (count == 0)
+ return new String();
+ if (offset < 0 || count < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String data = getData();
+ if (data == null) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ int length = data.length();
+ if (offset == 0 && count == length)
+ return data;
+ if (offset > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ int end = offset + count;
+ if (end > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ return data.substring(offset, end);
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(getNodeName());
+ buffer.append('(');
+ buffer.append(getData());
+ buffer.append(')');
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode != null) {
+ buffer.append('@');
+ buffer.append(flatNode.toString());
+ }
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java
new file mode 100644
index 0000000000..2d8d257072
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+
+
+/**
+ * CommentImpl class
+ */
+public class CommentImpl extends CharacterDataImpl implements Comment {
+
+ private boolean isJSPTag = false;
+
+ /**
+ * CommentImpl constructor
+ */
+ protected CommentImpl() {
+ super();
+ }
+
+ /**
+ * CommentImpl constructor
+ *
+ * @param that
+ * CommentImpl
+ */
+ protected CommentImpl(CommentImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.isJSPTag = that.isJSPTag;
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ CommentImpl cloned = new CommentImpl(this);
+ return cloned;
+ }
+
+ /**
+ * getData method
+ *
+ * @return java.lang.String
+ */
+ public String getData() throws DOMException {
+ String data = getCharacterData();
+ if (data == null) {
+ data = getData(getStructuredDocumentRegion());
+ if (data == null)
+ data = new String();
+ }
+ return data;
+ }
+
+ /**
+ */
+ private String getData(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return null;
+
+ ITextRegion contentRegion = null;
+ StringBuffer buffer = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_COMMENT_OPEN || regionType == JSP_COMMENT_OPEN || regionType == XMLRegionContext.XML_COMMENT_CLOSE || regionType == JSP_COMMENT_CLOSE) {
+ continue;
+ }
+ if (contentRegion == null) { // first content
+ contentRegion = region;
+ } else { // multiple contents
+ if (buffer == null) {
+ buffer = new StringBuffer(flatNode.getText(contentRegion));
+ }
+ buffer.append(flatNode.getText(region));
+ }
+ }
+
+ if (buffer != null)
+ return buffer.toString();
+ if (contentRegion != null)
+ return flatNode.getText(contentRegion);
+ return null;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return "#comment";//$NON-NLS-1$
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return COMMENT_NODE;
+ }
+
+ /**
+ */
+ public boolean isClosed() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return true; // will be generated
+ String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode);
+ return (regionType == XMLRegionContext.XML_COMMENT_CLOSE || regionType == XMLJSPRegionContexts.JSP_COMMENT_CLOSE);
+ }
+
+ /**
+ * isJSP method
+ *
+ * @return boolean
+ */
+ public boolean isJSPTag() {
+ return this.isJSPTag;
+ }
+
+ /**
+ * setJSPTag method
+ *
+ * @param isJSPTag
+ * boolean
+ */
+ public void setJSPTag(boolean isJSPTag) {
+ if (isJSPTag == this.isJSPTag)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (isJSPTag) {
+ if (document == null || !document.isJSPType())
+ return;
+ }
+
+ this.isJSPTag = isJSPTag;
+
+ if (getContainerDocument() != null) {
+ // already in the tree, update IStructuredDocument
+ setData(getData()); // calls notifyValueChanged();
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java
new file mode 100644
index 0000000000..06058a549f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+
+
+/**
+ * DocumentFragmentImpl class
+ */
+public class DocumentFragmentImpl extends NodeContainer implements DocumentFragment {
+
+ /**
+ * DocumentFragmentImpl constructor
+ */
+ protected DocumentFragmentImpl() {
+ super();
+ }
+
+ /**
+ * DocumentFragmentImpl constructor
+ *
+ * @param that
+ * DocumentFragmentImpl
+ */
+ protected DocumentFragmentImpl(DocumentFragmentImpl that) {
+ super(that);
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ DocumentFragmentImpl cloned = new DocumentFragmentImpl(this);
+ if (deep)
+ cloneChildNodes(cloned, deep);
+ return cloned;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return "#document-fragment";//$NON-NLS-1$
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return DOCUMENT_FRAGMENT_NODE;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java
new file mode 100644
index 0000000000..f4ca2cc236
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java
@@ -0,0 +1,1073 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+// for org.apache.xerces 3.2.1
+// import org.apache.xerces.utils.XMLCharacterProperties;
+// DMW modified for XML4J 4.0.1
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.wst.common.contentmodel.CMDocument;
+import org.eclipse.wst.common.contentmodel.CMEntityDeclaration;
+import org.eclipse.wst.common.contentmodel.CMNamedNodeMap;
+import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier;
+import org.eclipse.wst.sse.core.modelhandler.IModelHandler;
+import org.eclipse.wst.xml.core.NameValidator;
+import org.eclipse.wst.xml.core.commentelement.impl.CommentElementRegistry;
+import org.eclipse.wst.xml.core.document.DocumentTypeAdapter;
+import org.eclipse.wst.xml.core.document.JSPTag;
+import org.eclipse.wst.xml.core.document.XMLCharEntity;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Entity;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Notation;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.w3c.dom.ranges.Range;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+import org.w3c.dom.traversal.TreeWalker;
+
+
+/**
+ * DocumentImpl class
+ */
+public class DocumentImpl extends NodeContainer implements XMLDocument {
+
+ /**
+ * Internal-use only class. This class was added to better able to handle
+ * repetetive request for getElementsByTagName. The cache is cleared when
+ * ever the document changes at all, so still not real efficient,
+ */
+ class TagNameCache {
+
+ private boolean active = true;
+
+ private Map cache;
+
+ public TagNameCache() {
+ super();
+ cache = new HashMap();
+ }
+
+ /**
+ * @param b
+ */
+ public void activate(boolean b) {
+ active = b;
+ if (!b)
+ clear();
+ }
+
+ public void addItem(String tagname, NodeListImpl nodelist) {
+ if (tagname == null || nodelist == null)
+ return;
+ cache.put(tagname, nodelist);
+ }
+
+ public void clear() {
+ cache.clear();
+ }
+
+ public NodeListImpl getItem(String tagName) {
+ NodeListImpl result = null;
+ if (active) {
+ result = (NodeListImpl) cache.get(tagName);
+ // if (result != null) {
+ // System.out.println("getElementsByTagname from cache: " +
+ // tagName);
+ // }
+ }
+ return result;
+ }
+
+ }
+
+ // this is a constant just to give compile-time control over
+ // whether or not to use the cache. If, in future, its found that
+ // there are no (or few) "duplicate requests" ... then this cache
+ // is not needed.
+ private static final boolean usetagnamecache = true;
+ private DocumentTypeAdapter documentTypeAdapter = null;
+
+ private XMLModelImpl model = null;
+ private TagNameCache tagNameCache;
+
+ /**
+ * DocumentImpl constructor
+ */
+ protected DocumentImpl() {
+ super();
+ if (usetagnamecache) {
+ tagNameCache = new TagNameCache();
+ }
+ }
+
+ /**
+ * DocumentImpl constructor
+ *
+ * @param that
+ * DocumentImpl
+ */
+ protected DocumentImpl(DocumentImpl that) {
+ super(that);
+ if (usetagnamecache) {
+ tagNameCache = new TagNameCache();
+ }
+ }
+
+ /**
+ * @param b
+ */
+ void activateTagNameCache(boolean b) {
+ tagNameCache.activate(b);
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * Changes the <code>ownerDocument</code> of a node, its children, as
+ * well as the attached attribute nodes if there are any. If the node has
+ * a parent it is first removed from its parent child list. This
+ * effectively allows moving a subtree from one document to another. The
+ * following list describes the specifics for each type of node.
+ * <dl>
+ * <dt>ATTRIBUTE_NODE</dt>
+ * <dd>The <code>ownerElement</code> attribute is set to
+ * <code>null</code> and the <code>specified</code> flag is set to
+ * <code>true</code> on the adopted <code>Attr</code>. The
+ * descendants of the source <code>Attr</code> are recursively adopted.
+ * </dd>
+ * <dt>DOCUMENT_FRAGMENT_NODE</dt>
+ * <dd>The descendants of the source node are recursively adopted.</dd>
+ * <dt>DOCUMENT_NODE</dt>
+ * <dd><code>Document</code> nodes cannot be adopted.</dd>
+ * <dt>DOCUMENT_TYPE_NODE</dt>
+ * <dd><code>DocumentType</code> nodes cannot be adopted.</dd>
+ * <dt>ELEMENT_NODE</dt>
+ * <dd>Specified attribute nodes of the source element are adopted, and
+ * the generated <code>Attr</code> nodes. Default attributes are
+ * discarded, though if the document being adopted into defines default
+ * attributes for this element name, those are assigned. The descendants
+ * of the source element are recursively adopted.</dd>
+ * <dt>ENTITY_NODE</dt>
+ * <dd><code>Entity</code> nodes cannot be adopted.</dd>
+ * <dt>ENTITY_REFERENCE_NODE</dt>
+ * <dd>Only the <code>EntityReference</code> node itself is adopted,
+ * the descendants are discarded, since the source and destination
+ * documents might have defined the entity differently. If the document
+ * being imported into provides a definition for this entity name, its
+ * value is assigned.</dd>
+ * <dt>NOTATION_NODE</dt>
+ * <dd><code>Notation</code> nodes cannot be adopted.</dd>
+ * <dt>PROCESSING_INSTRUCTION_NODE, TEXT_NODE, CDATA_SECTION_NODE,
+ * COMMENT_NODE</dt>
+ * <dd>These nodes can all be adopted. No specifics.</dd>
+ * Should this method simply return null when it fails? How "exceptional"
+ * is failure for this method?Stick with raising exceptions only in
+ * exceptional circumstances, return null on failure (F2F 19 Jun 2000).Can
+ * an entity node really be adopted?No, neither can Notation nodes (Telcon
+ * 13 Dec 2000).Does this affect keys and hashCode's of the adopted
+ * subtree nodes?If so, what about readonly-ness of key and hashCode?if
+ * not, would appendChild affect keys/hashCodes or would it generate
+ * exceptions if key's are duplicate? Update: Hashcodes have been dropped.
+ * Given that the key is only unique within a document an adopted node
+ * needs to be given a new key, but what does it mean for the application?
+ *
+ * @param source
+ * The node to move into this document.
+ * @return The adopted node, or <code>null</code> if this operation
+ * fails, such as when the source node comes from a different
+ * implementation.
+ * @exception DOMException
+ * NOT_SUPPORTED_ERR: Raised if the source node is of type
+ * <code>DOCUMENT</code>,<code>DOCUMENT_TYPE</code>.
+ * <br>
+ * NO_MODIFICATION_ALLOWED_ERR: Raised when the source node
+ * is readonly.
+ * @since DOM Level 3
+ */
+ public org.w3c.dom.Node adoptNode(org.w3c.dom.Node source) throws org.w3c.dom.DOMException {
+ return null;
+ }
+
+ /**
+ * @param tagName
+ */
+ protected void checkTagNameValidity(String tagName) {
+ if (!isValidName(tagName)) {
+ throw new DOMException(DOMException.INVALID_CHARACTER_ERR, createDOMExceptionMessage(DOMException.INVALID_CHARACTER_ERR, tagName));
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ DocumentImpl cloned = new DocumentImpl(this);
+ if (deep)
+ cloned.importChildNodes(this, true);
+ return cloned;
+ }
+
+ /**
+ * createAttribute method
+ *
+ * @return org.w3c.dom.Attr
+ * @param name
+ * java.lang.String
+ */
+ public Attr createAttribute(String name) throws DOMException {
+ AttrImpl attr = new AttrImpl();
+ attr.setOwnerDocument(this);
+ attr.setName(name);
+ return attr;
+ }
+
+ /**
+ */
+ public Attr createAttributeNS(String uri, String name) throws DOMException {
+ AttrImpl attr = new AttrImpl();
+ attr.setOwnerDocument(this);
+ attr.setName(name);
+ attr.setNamespaceURI(uri);
+ return attr;
+ }
+
+ /**
+ * createCDATASection method
+ *
+ * @return org.w3c.dom.CDATASection
+ * @param data
+ * java.lang.String
+ */
+ public CDATASection createCDATASection(String data) throws DOMException {
+ // allow CDATA section
+ // if (!isXMLType()) {
+ // throw new DOMException(DOMException.NOT_SUPPORTED_ERR, new
+ // String());
+ // }
+ CDATASectionImpl cdata = new CDATASectionImpl();
+ cdata.setOwnerDocument(this);
+ if (data != null)
+ cdata.setData(data);
+ return cdata;
+ }
+
+ /**
+ * createComment method
+ *
+ * @return org.w3c.dom.Comment
+ * @param data
+ * java.lang.String
+ */
+ public Comment createComment(String data) {
+ CommentImpl comment = new CommentImpl();
+ comment.setOwnerDocument(this);
+ if (data != null)
+ comment.setData(data);
+ return comment;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.model.xml.XMLDocument#createCommentElement(java.lang.String,
+ * boolean)
+ */
+ public Element createCommentElement(String tagName, boolean isJSPTag) throws DOMException {
+ if (!isJSPType() && isJSPTag) {
+ throw new DOMException(DOMException.INVALID_MODIFICATION_ERR, new String());
+ }
+ ElementImpl element = (ElementImpl) createElement(tagName);
+ element.setJSPTag(isJSPTag);
+ CommentElementRegistry registry = CommentElementRegistry.getInstance();
+ if (registry.setupCommentElement(element)) {
+ return element;
+ } else {
+ throw new DOMException(DOMException.INVALID_CHARACTER_ERR, new String());
+ }
+ }
+
+ /**
+ * createDoctype method
+ *
+ * @return org.w3c.dom.DocumentType
+ * @param name
+ * java.lang.String
+ */
+ public DocumentType createDoctype(String name) {
+ DocumentTypeImpl docType = new DocumentTypeImpl();
+ docType.setOwnerDocument(this);
+ docType.setName(name);
+ return docType;
+ }
+
+ /**
+ * createDocumentFragment method
+ *
+ * @return org.w3c.dom.DocumentFragment
+ */
+ public DocumentFragment createDocumentFragment() {
+ DocumentFragmentImpl fragment = new DocumentFragmentImpl();
+ fragment.setOwnerDocument(this);
+ return fragment;
+ }
+
+ /**
+ * createElement method
+ *
+ * @return org.w3c.dom.Element
+ * @param tagName
+ * java.lang.String
+ */
+ public Element createElement(String tagName) throws DOMException {
+ checkTagNameValidity(tagName);
+
+ ElementImpl element = new ElementImpl();
+ element.setOwnerDocument(this);
+ element.setTagName(tagName);
+ return element;
+ }
+
+ /**
+ */
+ public Element createElementNS(String uri, String tagName) throws DOMException {
+ if (!isValidName(tagName)) {
+ throw new DOMException(DOMException.INVALID_CHARACTER_ERR, new String());
+ }
+
+ ElementImpl element = new ElementImpl();
+ element.setOwnerDocument(this);
+ element.setTagName(tagName);
+ element.setNamespaceURI(uri);
+ return element;
+ }
+
+ /**
+ * createEntity method
+ *
+ * @return org.w3c.dom.Entity
+ * @param name
+ * java.lang.String
+ */
+ public Entity createEntity(String name) {
+ EntityImpl entity = new EntityImpl();
+ entity.setOwnerDocument(this);
+ entity.setName(name);
+ return entity;
+ }
+
+ /**
+ * createEntityReference method
+ *
+ * @return org.w3c.dom.EntityReference
+ * @param name
+ * java.lang.String
+ */
+ public EntityReference createEntityReference(String name) throws DOMException {
+ if (!isXMLType()) {
+ throw new DOMException(DOMException.NOT_SUPPORTED_ERR, new String());
+ }
+
+ EntityReferenceImpl ref = new EntityReferenceImpl();
+ ref.setOwnerDocument(this);
+ ref.setName(name);
+ return ref;
+ }
+
+ /**
+ */
+ public NodeIterator createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) {
+ if (root == null)
+ root = this;
+ return new NodeIteratorImpl(root, whatToShow, filter);
+ }
+
+ /**
+ * createNotation method
+ *
+ * @return org.w3c.dom.Notation
+ * @param name
+ * java.lang.String
+ */
+ public Notation createNotation(String name) {
+ NotationImpl notation = new NotationImpl();
+ notation.setOwnerDocument(this);
+ notation.setName(name);
+ return notation;
+ }
+
+ /**
+ * createProcessingInstruction method
+ *
+ * @return org.w3c.dom.ProcessingInstruction
+ * @param target
+ * java.lang.String
+ * @param data
+ * java.lang.String
+ */
+ public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException {
+ ProcessingInstructionImpl pi = new ProcessingInstructionImpl();
+ pi.setOwnerDocument(this);
+ pi.setTarget(target);
+ if (data != null)
+ pi.setData(data);
+ return pi;
+ }
+
+ /**
+ */
+ public Range createRange() {
+ return new RangeImpl();
+ }
+
+ /**
+ * createTextNode method
+ *
+ * @return org.w3c.dom.Text
+ * @param data
+ * java.lang.String
+ */
+ public Text createTextNode(String data) {
+ TextImpl text = new TextImpl();
+ text.setOwnerDocument(this);
+ text.setData(data);
+ return text;
+ }
+
+ /**
+ */
+ public TreeWalker createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) {
+ // not suppoerted
+ return null;
+ }
+
+ private DocumentType findDoctype(Node node) {
+ for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child.getNodeType() == DOCUMENT_TYPE_NODE && child instanceof DocumentType) {
+ return (DocumentType) child;
+ } else if (child.getNodeType() == ELEMENT_NODE && ((XMLElement) child).isCommentTag()) {
+ // search DOCTYPE inside of generic comment element
+ DocumentType docType = findDoctype(child);
+ if (docType != null) {
+ return docType;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Element findDocumentElement(String docName, Node node, Node[] firstFound) {
+ for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child.getNodeType() != ELEMENT_NODE)
+ continue;
+ ElementImpl element = (ElementImpl) child;
+ if (element.isCommentTag()) {
+ Element docElement = findDocumentElement(docName, element, firstFound);
+ if (docElement != null) {
+ return docElement;
+ } else {
+ // added 'else continue' to better handle cases where
+ // there is "more than one root" element
+ // especially complicated by CommentElements, which are
+ // sometimes treated as elements, but should
+ // be treated as comments in this context.
+ continue;
+ }
+ }
+ // note: the "name" won't match in the event of a jsp tag ... but
+ // incase
+ // the name is null, we do not want the jsp element returned as
+ // documentElement
+ if (element.isJSPTag())
+ continue;
+ if (docName == null)
+ return element;
+ // use local name for namespace
+ String localName = element.getLocalName();
+ if (localName == null)
+ continue;
+ if (isXMLType()) {
+ if (localName.equals(docName))
+ return element;
+ } else {
+ if (localName.equalsIgnoreCase(docName))
+ return element;
+ }
+ if (firstFound[0] == null)
+ firstFound[0] = element;
+ }
+ return null;
+ }
+
+ /**
+ * getCharValue method
+ *
+ * @return java.lang.String
+ * @param name
+ * java.lang.String
+ */
+ protected String getCharValue(String name) {
+ if (name == null)
+ return null;
+ int length = name.length();
+ if (length == 0)
+ return null;
+
+ if (name.charAt(0) == '#') { // character reference
+ if (length == 1)
+ return null;
+ int radix = 10;
+ String s = null;
+ // now allow hexadecimal also for non XML document
+ if (name.charAt(1) == 'x') { // hexadecimal
+ radix = 16;
+ s = name.substring(2);
+ } else { // decimal
+ s = name.substring(1);
+ }
+ if (s == null || s.length() == 0)
+ return null;
+ if (s.charAt(0) == '-')
+ return null; // no minus accepted
+ char c = 0;
+ try {
+ c = (char) Integer.parseInt(s, radix);
+ } catch (NumberFormatException ex) {
+ }
+ if (c == 0)
+ return null;
+ return String.valueOf(c);
+ }
+
+ // implicit character entities for XML
+ if (name.equals(XMLCharEntity.LT_NAME))
+ return XMLCharEntity.LT_VALUE;
+ if (name.equals(XMLCharEntity.GT_NAME))
+ return XMLCharEntity.GT_VALUE;
+ if (name.equals(XMLCharEntity.AMP_NAME))
+ return XMLCharEntity.AMP_VALUE;
+ if (name.equals(XMLCharEntity.QUOT_NAME))
+ return XMLCharEntity.QUOT_VALUE;
+ if (isXMLType()) {
+ if (name.equals(XMLCharEntity.APOS_NAME))
+ return XMLCharEntity.APOS_VALUE;
+ }
+
+ CMDocument cm = getCMDocument();
+ if (cm != null) {
+ CMNamedNodeMap map = cm.getEntities();
+ if (map != null) {
+ CMEntityDeclaration decl = (CMEntityDeclaration) map.getNamedItem(name);
+ if (decl != null) {
+ String value = decl.getValue();
+ if (value == null)
+ return null;
+ int valueLength = value.length();
+ if (valueLength > 1 && value.charAt(0) == '&' && value.charAt(1) == '#' && value.charAt(valueLength - 1) == ';') {
+ // character reference
+ return getCharValue(value.substring(1, valueLength - 1));
+ }
+ return value;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ */
+ protected CMDocument getCMDocument() {
+ ModelQuery modelQuery = ModelQueryUtil.getModelQuery(this);
+ if (modelQuery == null)
+ return null;
+ return modelQuery.getCorrespondingCMDocument(this);
+ }
+
+ /**
+ * getDoctype method
+ *
+ * @return org.w3c.dom.DocumentType
+ */
+ public DocumentType getDoctype() {
+ return findDoctype(this);
+ }
+
+ /**
+ * getDocumentElement
+ *
+ * @return org.w3c.dom.Element From DOM 2 Spec: documentElement of type
+ * Element [p.62] , readonly This is a convenience [p.119]
+ * attribute that allows direct access to the child node that is
+ * the root element of the document. For HTML documents, this is
+ * the element with the tagName "HTML". Note: we differ from this
+ * definition a little in that we don't necessarily take the first
+ * child but also look to match the name. In a well formed
+ * document, of course, the result is the same, but not
+ * necessarily the same in an ill-formed document.
+ */
+ public Element getDocumentElement() {
+ String name = null;
+ DocumentType docType = getDocumentType();
+ if (docType != null) {
+ name = docType.getName();
+ }
+
+ Element first[] = new Element[1];
+ Element docElement = findDocumentElement(name, this, first);
+ if (docElement == null) {
+ docElement = first[0];
+ }
+
+ return docElement;
+ }
+
+ /**
+ */
+ protected DocumentType getDocumentType() {
+ DocumentTypeAdapter adapter = getDocumentTypeAdapter();
+ if (adapter == null)
+ return getDoctype();
+ return adapter.getDocumentType();
+ }
+
+ /**
+ */
+ protected DocumentTypeAdapter getDocumentTypeAdapter() {
+ if (this.documentTypeAdapter == null) {
+ this.documentTypeAdapter = (DocumentTypeAdapter) getAdapterFor(DocumentTypeAdapter.class);
+ if (this.documentTypeAdapter == null) {
+ // add default adapter
+ this.documentTypeAdapter = new DocumentTypeAdapterImpl(this);
+ addAdapter(this.documentTypeAdapter);
+ }
+ }
+ return this.documentTypeAdapter;
+ }
+
+ /**
+ */
+ public String getDocumentTypeId() {
+ DocumentType docType = getDocumentType();
+ if (docType == null)
+ return null;
+ String id = docType.getPublicId();
+ if (id == null)
+ id = docType.getSystemId();
+ return id;
+ }
+
+ /**
+ */
+ public Element getElementById(String id) {
+ if (id == null)
+ return null;
+ NodeIterator it = createNodeIterator(this, NodeFilter.SHOW_ALL, null, false);
+ if (it == null)
+ return null;
+
+ for (Node node = it.nextNode(); node != null; node = it.nextNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ continue;
+ ElementImpl element = (ElementImpl) node;
+ String value = element.getAttribute("id");//$NON-NLS-1$
+ if (value != null && value.equals(id))
+ return element;
+ }
+
+ return null;
+ }
+
+ /**
+ * getElementsByTagName method
+ *
+ * @return org.w3c.dom.NodeList
+ * @param tagName
+ * java.lang.String
+ */
+ public NodeList getElementsByTagName(String tagName) {
+ if (tagName == null)
+ return new NodeListImpl();
+
+ NodeListImpl elements = null;
+
+ if (usetagnamecache) {
+ elements = tagNameCache.getItem(tagName);
+ }
+
+ if (elements == null) {
+ elements = internalGetElementsByTagName(tagName);
+
+ }
+
+ return elements;
+ }
+
+ /**
+ */
+ public NodeList getElementsByTagNameNS(String uri, String tagName) {
+ if (tagName == null)
+ return new NodeListImpl();
+
+ NodeIterator it = createNodeIterator(this, NodeFilter.SHOW_ALL, null, false);
+ if (it == null)
+ return new NodeListImpl();
+ NodeListImpl elements = new NodeListImpl();
+
+ if (uri != null && uri.length() == 1 && uri.charAt(0) == '*') {
+ uri = null; // do not care
+ }
+ if (tagName.length() == 1 && tagName.charAt(0) == '*') {
+ tagName = null; // do not care
+ }
+
+ for (Node node = it.nextNode(); node != null; node = it.nextNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ continue;
+ ElementImpl element = (ElementImpl) node;
+ if (tagName != null) {
+ String localName = element.getLocalName();
+ if (localName == null || !localName.equals(tagName))
+ continue;
+ }
+ if (uri != null) {
+ String nsURI = element.getNamespaceURI();
+ if (nsURI == null || !nsURI.equals(uri))
+ continue;
+ }
+ elements.appendNode(element);
+ }
+
+ return elements;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the XML declaration, the encoding
+ * of this document. This is <code>null</code> when unspecified.
+ *
+ * @since DOM Level 3
+ */
+ public java.lang.String getEncoding() {
+ return null;
+ }
+
+ /**
+ */
+ public DOMImplementation getImplementation() {
+ return model;
+ }
+
+ /**
+ * other nodes will be referring to this one to get the owning model
+ */
+ public XMLModel getModel() {
+ return model;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return "#document";//$NON-NLS-1$
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return DOCUMENT_NODE;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the XML declaration, whether this
+ * document is standalone.
+ *
+ * @since DOM Level 3
+ */
+ public boolean getStandalone() {
+ return false;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying whether errors checking is enforced or not.
+ * When set to <code>false</code>, the implementation is free to not
+ * test every possible error case normally defined on DOM operations, and
+ * not raise any <code>DOMException</code>. In case of error, the
+ * behavior is undefined. This attribute is <code>true</code> by
+ * defaults.
+ *
+ * @since DOM Level 3
+ */
+ public boolean getStrictErrorChecking() {
+ return false;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the XML declaration, the version
+ * number of this document. This is <code>null</code> when unspecified.
+ *
+ * @since DOM Level 3
+ */
+ public String getVersion() {
+ return null;
+ }
+
+ /**
+ */
+ protected boolean ignoreCase() {
+ DocumentTypeAdapter adapter = getDocumentTypeAdapter();
+ if (adapter == null)
+ return false;
+ return (adapter.getTagNameCase() != DocumentTypeAdapter.STRICT_CASE);
+ }
+
+ /**
+ */
+ protected void importChildNodes(Node parent, boolean deep) {
+ if (parent == null)
+ return;
+
+ removeChildNodes();
+
+ for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+ Node imported = importNode(child, deep);
+ if (imported == null)
+ continue;
+ appendChild(imported);
+ }
+ }
+
+ /**
+ */
+ public Node importNode(Node node, boolean deep) throws DOMException {
+ if (node == null)
+ return null;
+ NodeImpl imported = (NodeImpl) node.cloneNode(deep);
+ if (imported == null)
+ return null;
+ imported.setOwnerDocument(this, deep);
+ return imported;
+ }
+
+ private NodeListImpl internalGetElementsByTagName(String tagName) {
+ //System.out.println("getElementsByTagname: " + tagName);
+ NodeIterator it = createNodeIterator(this, NodeFilter.SHOW_ALL, null, false);
+ if (it == null)
+ return new NodeListImpl();
+ NodeListImpl elements = new NodeListImpl();
+
+ if (tagName.length() == 1 && tagName.charAt(0) == '*') {
+ tagName = null; // do not care
+ }
+
+ for (Node node = it.nextNode(); node != null; node = it.nextNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ continue;
+ if (tagName != null) {
+ ElementImpl element = (ElementImpl) node;
+ if (!element.matchTagName(tagName))
+ continue;
+ }
+ elements.appendNode(node);
+ }
+ if (usetagnamecache) {
+ tagNameCache.addItem(tagName, elements);
+ }
+ return elements;
+ }
+
+ /**
+ */
+ public boolean isJSPDocument() {
+ Element element = getDocumentElement();
+ if (element == null)
+ return false;
+ String tagName = element.getTagName();
+ if (tagName == null)
+ return false;
+ return tagName.equals(JSPTag.JSP_ROOT);
+ }
+
+ /**
+ */
+ public boolean isJSPType() {
+ if (this.model == null)
+ return false;
+ IModelHandler handler = this.model.getModelHandler();
+ if (handler == null)
+ return false;
+ String id = handler.getAssociatedContentTypeId();
+ if (id == null)
+ return false;
+ // TODO: -- avoid this semi hardcoded string
+ return id.equals(IContentTypeIdentifier.ContentTypeID_JSP);
+ }
+
+ /**
+ */
+ protected boolean isValidName(String name) {
+ if (name == null || name.length() == 0)
+ return false;
+ // // DMW: modified for XML4J 4.0.1
+ // if (XMLChar.isValidName(name)) return true;
+ if (NameValidator.isValid(name))
+ return true;
+ // special for invalid declaration
+ if (name.length() == 1 && name.charAt(0) == '!')
+ return true;
+ // special for JSP tag in tag name
+ if (name.startsWith(JSPTag.TAG_OPEN))
+ return true;
+ return false;
+ }
+
+ /**
+ */
+ public boolean isXMLType() {
+ DocumentTypeAdapter adapter = getDocumentTypeAdapter();
+ if (adapter == null)
+ return true;
+ return adapter.isXMLType();
+ }
+
+ /**
+ */
+ protected void releaseDocumentType() {
+ if (this.documentTypeAdapter == null)
+ return;
+ this.documentTypeAdapter.release();
+ this.documentTypeAdapter = null;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the XML declaration, the encoding
+ * of this document. This is <code>null</code> when unspecified.
+ *
+ * @since DOM Level 3
+ */
+ public void setEncoding(java.lang.String encoding) {
+ }
+
+ /**
+ * setModel method
+ *
+ * @param model
+ * XMLModel
+ */
+
+ protected void setModel(XMLModel model) {
+ this.model = (XMLModelImpl) model;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the XML declaration, whether this
+ * document is standalone.
+ *
+ * @since DOM Level 3
+ */
+ public void setStandalone(boolean standalone) {
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying whether errors checking is enforced or not.
+ * When set to <code>false</code>, the implementation is free to not
+ * test every possible error case normally defined on DOM operations, and
+ * not raise any <code>DOMException</code>. In case of error, the
+ * behavior is undefined. This attribute is <code>true</code> by
+ * defaults.
+ *
+ * @since DOM Level 3
+ */
+ public void setStrictErrorChecking(boolean strictErrorChecking) {
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the XML declaration, the version
+ * number of this document. This is <code>null</code> when unspecified.
+ *
+ * @since DOM Level 3
+ */
+ public void setVersion(java.lang.String version) {
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java
new file mode 100644
index 0000000000..8d63d99b79
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.xml.core.document.DocumentTypeAdapter;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.w3c.dom.DocumentType;
+
+
+/**
+ */
+public class DocumentTypeAdapterImpl implements DocumentTypeAdapter {
+
+ private XMLDocument document = null;
+ private DocumentType documentType = null;
+
+ /**
+ */
+ protected DocumentTypeAdapterImpl() {
+ super();
+ }
+
+ /**
+ */
+ protected DocumentTypeAdapterImpl(XMLDocument document) {
+ this.document = document;
+ if (document != null) {
+ this.documentType = document.getDoctype();
+ }
+ }
+
+ /**
+ */
+ public int getAttrNameCase() {
+ return STRICT_CASE;
+ }
+
+ /**
+ */
+ protected XMLDocument getDocument() {
+ return this.document;
+ }
+
+ /**
+ */
+ public DocumentType getDocumentType() {
+ return this.documentType;
+ }
+
+ /**
+ */
+ public int getTagNameCase() {
+ return STRICT_CASE;
+ }
+
+ /**
+ */
+ public boolean hasFeature(String feature) {
+ return false;
+ }
+
+ /**
+ */
+ public boolean isAdapterForType(Object type) {
+ return (type == DocumentTypeAdapter.class);
+ }
+
+ /**
+ */
+ public boolean isXMLType() {
+ return true;
+ }
+
+ /**
+ */
+ public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ if (eventType != INodeNotifier.STRUCTURE_CHANGED)
+ return;
+ if (notifier == null || !(notifier instanceof XMLDocument))
+ return;
+ this.documentType = ((XMLDocument) notifier).getDoctype();
+ }
+
+ /**
+ */
+ protected void notifyDocumentTypeChanged() {
+ if (this.document == null)
+ return;
+ XMLModel model = this.document.getModel();
+ if (model == null)
+ return;
+ ((XMLModelImpl) model).documentTypeChanged();
+ }
+
+ /**
+ */
+ public void release() {
+ // nothing to do
+ }
+
+ /**
+ */
+ protected void setDocumentType(DocumentType documentType) {
+ this.documentType = documentType;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java
new file mode 100644
index 0000000000..c8137da34b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.document.XMLDocumentType;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+
+/**
+ * DocumentType class
+ */
+public class DocumentTypeImpl extends NodeImpl implements XMLDocumentType {
+ private String internalSubset = null;
+
+ private String name = null;
+ private String publicId = null;
+ private String systemId = null;
+
+ /**
+ * DocumentTypeImpl constructor
+ */
+ protected DocumentTypeImpl() {
+ super();
+ }
+
+ /**
+ * DocumentTypeImpl constructor
+ *
+ * @param that
+ * DocumentTypeImpl
+ */
+ protected DocumentTypeImpl(DocumentTypeImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.name = that.name;
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ DocumentTypeImpl cloned = new DocumentTypeImpl(this);
+ return cloned;
+ }
+
+ /**
+ * getEntities method
+ *
+ * @return org.w3c.dom.NamedNodeMap
+ */
+ public NamedNodeMap getEntities() {
+ return null;
+ }
+
+ /**
+ */
+ public String getInternalSubset() {
+ return this.internalSubset;
+ }
+
+ /**
+ * getName method
+ *
+ * @return java.lang.String
+ */
+ public String getName() {
+ if (this.name == null)
+ return new String();
+ return this.name;
+ }
+
+ /**
+ * getNodeName
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return getName();
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return DOCUMENT_TYPE_NODE;
+ }
+
+ /**
+ * getNotations method
+ *
+ * @return org.w3c.dom.NamedNodeMap
+ */
+ public NamedNodeMap getNotations() {
+ return null;
+ }
+
+ /**
+ * getPublicId method
+ *
+ * @return java.lang.String
+ */
+ public String getPublicId() {
+ return this.publicId;
+ }
+
+ /**
+ * getSystemId method
+ *
+ * @return java.lang.String
+ */
+ public String getSystemId() {
+ return this.systemId;
+ }
+
+ /**
+ */
+ public boolean isClosed() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return true; // will be generated
+ String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode);
+ return (regionType == XMLRegionContext.XML_DOCTYPE_DECLARATION_CLOSE || regionType == XMLRegionContext.XML_DECLARATION_CLOSE);
+ }
+
+ /**
+ */
+ public void setInternalSubset(String internalSubset) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.internalSubset = internalSubset;
+ }
+
+ /**
+ * setName method
+ *
+ * @param name
+ * java.lang.String
+ */
+ protected void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * setPublicId method
+ *
+ * @param publicId
+ * java.lang.String
+ */
+ public void setPublicId(String publicId) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.publicId = publicId;
+
+ notifyValueChanged();
+ }
+
+ /**
+ * setSystemId method
+ *
+ * @param systemId
+ * java.lang.String
+ */
+ public void setSystemId(String systemId) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.systemId = systemId;
+
+ notifyValueChanged();
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(getName());
+ buffer.append('(');
+ buffer.append(getPublicId());
+ buffer.append(')');
+ buffer.append('(');
+ buffer.append(getSystemId());
+ buffer.append(')');
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode != null) {
+ buffer.append('@');
+ buffer.append(flatNode.toString());
+ }
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java
new file mode 100644
index 0000000000..fd8d27a8ce
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java
@@ -0,0 +1,1421 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.sse.core.parser.RegionParser;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.commentelement.CommentElementAdapter;
+import org.eclipse.wst.xml.core.document.JSPTag;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.document.XMLNamespace;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+
+/**
+ * ElementImpl class
+ */
+public class ElementImpl extends NodeContainer implements XMLElement {
+
+ private class Attributes implements NamedNodeMap {
+ Attributes() {
+ super();
+ }
+
+ public int getLength() {
+ if (attrNodes == null)
+ return 0;
+ return attrNodes.getLength();
+ }
+
+ public Node getNamedItem(String name) {
+ return getAttributeNode(name);
+ }
+
+ public Node getNamedItemNS(String uri, String name) {
+ return getAttributeNodeNS(uri, name);
+ }
+
+ public Node item(int index) {
+ if (attrNodes == null)
+ return null;
+ return attrNodes.item(index);
+ }
+
+ public Node removeNamedItem(String name) throws DOMException {
+ return removeAttributeNode(name);
+ }
+
+ public Node removeNamedItemNS(String uri, String name) throws DOMException {
+ return removeAttributeNodeNS(uri, name);
+ }
+
+ public Node setNamedItem(Node arg) throws DOMException {
+ return setAttributeNode((AttrImpl) arg);
+ }
+
+ public Node setNamedItemNS(Node arg) throws DOMException {
+ return setAttributeNodeNS((AttrImpl) arg);
+ }
+ }
+
+ NodeListImpl attrNodes = null;
+ private IStructuredDocumentRegion endStructuredDocumentRegion = null;
+ private boolean isCommentTag = false;
+ private boolean isEmptyTag = false;
+ private boolean isJSPTag = false;
+ private String namespaceURI = null;
+
+ private String tagName = null;
+
+ /**
+ * ElementImpl constructor
+ */
+ protected ElementImpl() {
+ super();
+ }
+
+ /**
+ * ElementImpl constructor
+ *
+ * @param that
+ * ElementImpl
+ */
+ protected ElementImpl(ElementImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.tagName = that.tagName;
+ this.isEmptyTag = that.isEmptyTag;
+ this.isJSPTag = that.isJSPTag;
+ this.isCommentTag = that.isCommentTag;
+
+ // clone attributes
+ that.cloneAttributes(this);
+ }
+ }
+
+ /**
+ * addEndTag method
+ *
+ * @param end
+ * org.w3c.dom.Element
+ */
+ protected void addEndTag(Element endTag) {
+ if (endTag == null)
+ return;
+ if (hasEndTag())
+ return;
+ ElementImpl end = (ElementImpl) endTag;
+
+ // move the end flat node from the end tag
+ IStructuredDocumentRegion flatNode = end.getEndStructuredDocumentRegion();
+ if (flatNode == null)
+ return;
+ end.setEndStructuredDocumentRegion(null);
+ setEndStructuredDocumentRegion(flatNode);
+ }
+
+ /**
+ * appendAttibuteNode method
+ *
+ * @return org.w3c.dom.Attr
+ * @param newAttr
+ * org.w3c.dom.Attr
+ */
+ public Attr appendAttributeNode(Attr newAttr) {
+ if (newAttr == null)
+ return null;
+ AttrImpl attr = (AttrImpl) newAttr;
+ if (attr.getOwnerElement() != null)
+ return null;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ if (this.attrNodes == null)
+ this.attrNodes = new NodeListImpl();
+ this.attrNodes.appendNode(attr);
+ attr.setOwnerElement(this);
+
+ notifyAttrReplaced(attr, null);
+ return attr;
+ }
+
+ /**
+ * cloneAttributes method
+ *
+ * @param newOwner
+ * org.w3c.dom.Element
+ */
+ protected void cloneAttributes(Element newOwner) {
+ if (newOwner == null || newOwner == this)
+ return;
+
+ ElementImpl element = (ElementImpl) newOwner;
+ element.removeAttributes();
+
+ if (this.attrNodes == null)
+ return;
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ Node node = this.attrNodes.item(i);
+ if (node == null)
+ continue;
+ Attr cloned = (Attr) node.cloneNode(false);
+ if (cloned != null)
+ element.appendAttributeNode(cloned);
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ ElementImpl cloned = new ElementImpl(this);
+ if (deep)
+ cloneChildNodes(cloned, deep);
+ return cloned;
+ }
+
+ /**
+ * getAttribute method
+ *
+ * @return java.lang.String
+ * @param name
+ * java.lang.String
+ */
+ public String getAttribute(String name) {
+ Attr attr = getAttributeNode(name);
+ if (attr == null)
+ return null;
+ return attr.getValue();
+ }
+
+ /**
+ * getAttributeNode method
+ *
+ * @return org.w3c.dom.Attr
+ * @param name
+ * java.lang.String
+ */
+ public Attr getAttributeNode(String name) {
+ if (name == null)
+ return null; // invalid parameter
+ if (this.attrNodes == null)
+ return null; // no attribute
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr == null)
+ continue;
+ if (attr.matchName(name))
+ return attr; // found
+ }
+
+ return null; // not found
+ }
+
+ /**
+ */
+ public Attr getAttributeNodeNS(String uri, String name) {
+ if (name == null)
+ return null; // invalid parameter
+ if (this.attrNodes == null)
+ return null; // no attribute
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr == null)
+ continue;
+ String localName = attr.getLocalName();
+ if (localName == null || !localName.equals(name))
+ continue;
+ String nsURI = attr.getNamespaceURI();
+ if (uri == null) {
+ if (nsURI != null)
+ continue;
+ } else {
+ if (nsURI == null || !nsURI.equals(uri))
+ continue;
+ }
+
+ // found
+ return attr;
+ }
+
+ return null; // not found
+ }
+
+ /**
+ */
+ public String getAttributeNS(String uri, String name) {
+ Attr attr = getAttributeNodeNS(uri, name);
+ if (attr == null)
+ return null;
+ return attr.getValue();
+ }
+
+ /**
+ * getAttributes method
+ *
+ * @return org.w3c.dom.NamedNodeMap
+ */
+ public NamedNodeMap getAttributes() {
+ return new Attributes();
+ }
+
+ /**
+ */
+ protected CMElementDeclaration getDeclaration() {
+ Document document = getOwnerDocument();
+ if (document == null)
+ return null;
+ ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document);
+ if (modelQuery == null)
+ return null;
+ return modelQuery.getCMElementDeclaration(this);
+ }
+
+ /**
+ * getElementsByTagName method
+ *
+ * @return org.w3c.dom.NodeList
+ * @param tagName
+ * java.lang.String
+ */
+ public NodeList getElementsByTagName(String tagName) {
+ if (tagName == null)
+ return new NodeListImpl();
+
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document == null)
+ return new NodeListImpl();
+ NodeIterator it = document.createNodeIterator(this, NodeFilter.SHOW_ALL, null, false);
+ if (it == null)
+ return new NodeListImpl();
+ NodeListImpl elements = new NodeListImpl();
+
+ if (tagName.length() == 1 && tagName.charAt(0) == '*') {
+ tagName = null; // do not care
+ }
+
+ for (Node node = it.nextNode(); node != null; node = it.nextNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ continue;
+ if (tagName != null) {
+ ElementImpl element = (ElementImpl) node;
+ if (!element.matchTagName(tagName))
+ continue;
+ }
+ elements.appendNode(node);
+ }
+
+ return elements;
+ }
+
+ /**
+ */
+ public NodeList getElementsByTagNameNS(String uri, String tagName) {
+ if (tagName == null)
+ return new NodeListImpl();
+
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document == null)
+ return new NodeListImpl();
+ NodeIterator it = document.createNodeIterator(this, NodeFilter.SHOW_ALL, null, false);
+ if (it == null)
+ return new NodeListImpl();
+ NodeListImpl elements = new NodeListImpl();
+
+ if (uri != null && uri.length() == 1 && uri.charAt(0) == '*') {
+ uri = null; // do not care
+ }
+ if (tagName.length() == 1 && tagName.charAt(0) == '*') {
+ tagName = null; // do not care
+ }
+
+ for (Node node = it.nextNode(); node != null; node = it.nextNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ continue;
+ ElementImpl element = (ElementImpl) node;
+ if (tagName != null) {
+ String localName = element.getLocalName();
+ if (localName == null || !localName.equals(tagName))
+ continue;
+ }
+ if (uri != null) {
+ String nsURI = element.getNamespaceURI();
+ if (nsURI == null || !nsURI.equals(uri))
+ continue;
+ }
+ elements.appendNode(element);
+ }
+
+ return elements;
+ }
+
+ /**
+ * getEndOffset method
+ *
+ * @return int
+ */
+ public int getEndOffset() {
+ if (this.endStructuredDocumentRegion != null)
+ return this.endStructuredDocumentRegion.getEnd();
+ return super.getEndOffset();
+ }
+
+ /**
+ * getEndStartOffset method
+ *
+ * @return int
+ */
+ public int getEndStartOffset() {
+ if (this.endStructuredDocumentRegion != null)
+ return this.endStructuredDocumentRegion.getStart();
+ return super.getEndOffset();
+ }
+
+ /**
+ * getEndStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getEndStructuredDocumentRegion() {
+ return this.endStructuredDocumentRegion;
+ }
+
+ /**
+ */
+ public String getEndTagName() {
+ if (this.endStructuredDocumentRegion == null)
+ return null;
+
+ ITextRegionList regions = this.endStructuredDocumentRegion.getRegions();
+ if (regions == null)
+ return null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == XMLJSPRegionContexts.JSP_ROOT_TAG_NAME || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_NAME) {
+ return this.endStructuredDocumentRegion.getText(region);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * getFirstStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getFirstStructuredDocumentRegion() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode != null)
+ return StructuredDocumentRegionUtil.getStructuredDocumentRegion(flatNode);
+ return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.endStructuredDocumentRegion);
+ }
+
+ /**
+ * getLastStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getLastStructuredDocumentRegion() {
+ if (this.endStructuredDocumentRegion != null)
+ return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.endStructuredDocumentRegion);
+ return StructuredDocumentRegionUtil.getStructuredDocumentRegion(getStructuredDocumentRegion());
+ }
+
+ /**
+ */
+ public String getLocalName() {
+ if (this.tagName == null)
+ return null;
+ int index = this.tagName.indexOf(':');
+ if (index < 0)
+ return this.tagName;
+ return this.tagName.substring(index + 1);
+ }
+
+ /**
+ */
+ public String getNamespaceURI() {
+ String nsAttrName = null;
+ String prefix = getPrefix();
+ if (prefix != null && prefix.length() > 0) {
+ nsAttrName = XMLNamespace.XMLNS_PREFIX + prefix;
+ } else {
+ nsAttrName = XMLNamespace.XMLNS;
+ }
+
+ for (Node node = this; node != null; node = node.getParentNode()) {
+ if (node.getNodeType() != ELEMENT_NODE)
+ break;
+ Element element = (Element) node;
+ Attr attr = element.getAttributeNode(nsAttrName);
+ if (attr != null)
+ return attr.getValue();
+ }
+
+ return this.namespaceURI;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return getTagName();
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return ELEMENT_NODE;
+ }
+
+ /**
+ */
+ public String getPrefix() {
+ if (this.tagName == null)
+ return null;
+ int index = this.tagName.indexOf(':');
+ if (index <= 0)
+ return null;
+ // exclude JSP tag in tag name
+ if (this.tagName.charAt(0) == '<')
+ return null;
+ return this.tagName.substring(0, index);
+ }
+
+ /**
+ * getStartEndOffset method
+ *
+ * @return int
+ */
+ public int getStartEndOffset() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode != null)
+ return flatNode.getEnd();
+ return super.getStartOffset();
+ }
+
+ /**
+ * getStartOffset method
+ *
+ * @return int
+ */
+ public int getStartOffset() {
+ if (getStartStructuredDocumentRegion() == null && this.endStructuredDocumentRegion != null && !hasChildNodes()) {
+ return this.endStructuredDocumentRegion.getStart();
+ }
+ return super.getStartOffset();
+ }
+
+ /**
+ * getStartStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getStartStructuredDocumentRegion() {
+ return getStructuredDocumentRegion();
+ }
+
+ /**
+ * getTagName method
+ *
+ * @return java.lang.String
+ */
+ public String getTagName() {
+ if (this.tagName == null)
+ return new String();
+ return this.tagName;
+ }
+
+ /**
+ */
+ public boolean hasAttribute(String name) {
+ return (getAttributeNode(name) != null);
+ }
+
+ /**
+ */
+ public boolean hasAttributeNS(String uri, String name) {
+ return (getAttributeNodeNS(uri, name) != null);
+ }
+
+ /**
+ */
+ public boolean hasAttributes() {
+ return (this.attrNodes != null && this.attrNodes.getLength() > 0);
+ }
+
+ /**
+ * hasEndTag method
+ *
+ * @return boolean
+ */
+ public boolean hasEndTag() {
+ return (this.endStructuredDocumentRegion != null);
+ }
+
+ /**
+ */
+ protected final boolean hasPrefix() {
+ if (this.tagName == null)
+ return false;
+ if (this.tagName.indexOf(':') <= 0)
+ return false;
+ // exclude JSP tag in tag name
+ if (this.tagName.charAt(0) == '<')
+ return false;
+ return true;
+ }
+
+ /**
+ * hasStartTag method
+ *
+ * @return boolean
+ */
+ public boolean hasStartTag() {
+ return (getStructuredDocumentRegion() != null);
+ }
+
+ /**
+ */
+ protected final boolean ignoreCase() {
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document != null && document.ignoreCase()) {
+ // even in case insensitive document, if having prefix, it's case
+ // sensitive tag
+ return !hasPrefix();
+ }
+ return false;
+ }
+
+ /**
+ */
+ protected Attr insertAttributeNode(Attr newAttr, int index) {
+ if (newAttr == null)
+ return null;
+ AttrImpl attr = (AttrImpl) newAttr;
+ if (attr.getOwnerElement() != null)
+ return null;
+
+ if (this.attrNodes == null)
+ this.attrNodes = new NodeListImpl();
+ this.attrNodes.insertNode(attr, index);
+ attr.setOwnerElement(this);
+
+ notifyAttrReplaced(attr, null);
+ return attr;
+ }
+
+ /**
+ * insertBefore method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param refChild
+ * org.w3c.dom.Node
+ */
+ public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+ // should throw DOMException instead of return null?
+ if (newChild == null)
+ return null;
+ if (!isContainer()) { // never be container
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String());
+ }
+ if (newChild.getNodeType() != TEXT_NODE) {
+ if (isJSPContainer() || isCDATAContainer()) { // accepts only Text
+ // child
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String());
+ }
+ }
+ return super.insertBefore(newChild, refChild);
+ }
+
+ /**
+ */
+ protected boolean isCDATAContainer() {
+ // use BlockMaker instead of CMElementDeclaration
+ // because <style> and <script> in XHTML is not CDATA content type
+ XMLModel model = getModel();
+ if (model == null)
+ return false; // error
+ IStructuredDocument structuredDocument = model.getStructuredDocument();
+ if (structuredDocument == null)
+ return false; // eror
+ RegionParser parser = structuredDocument.getParser();
+ if (parser == null || !(parser instanceof XMLSourceParser))
+ return false;
+ return (((XMLSourceParser) parser).getBlockMarker(this.tagName) != null);
+ /*
+ * CMElementDeclaration decl = getDeclaration(); if (decl == null)
+ * return false; if (decl instanceof CMNodeWrapper) { decl =
+ * (CMElementDeclaration)((CMNodeWrapper)decl).getOriginNode(); if
+ * (decl == null) return false; } if (decl instanceof
+ * TLDElementDeclaration) { String content =
+ * ((TLDElementDeclaration)decl).getBodycontent(); if (content ==
+ * null) return false; return
+ * content.equals(JSP11TLDNames.CONTENT_TAGDEPENDENT); } if
+ * (!isGlobalTag()) return false; return (decl.getContentType() ==
+ * CMElementDeclaration.CDATA);
+ */
+ }
+
+ /**
+ */
+ public boolean isClosed() {
+ IStructuredDocumentRegion flatNode = null;
+ if (isEmptyTag() || !isContainer()) {
+ flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return true; // will be generated
+ } else {
+ flatNode = getEndStructuredDocumentRegion();
+ if (flatNode == null)
+ return false; // must be generated
+ }
+ String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode);
+ if (isCommentTag()) {
+ return (regionType == XMLJSPRegionContexts.JSP_COMMENT_CLOSE || regionType == XMLRegionContext.XML_COMMENT_CLOSE);
+ }
+ if (isJSPTag()) {
+ return (regionType == XMLJSPRegionContexts.JSP_CLOSE || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE);
+ }
+ return (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == XMLRegionContext.XML_DECLARATION_CLOSE);
+ }
+
+ /**
+ */
+ public final boolean isCommentTag() {
+ return this.isCommentTag;
+ }
+
+ /**
+ * isContainer method
+ *
+ * @return boolean
+ */
+ public boolean isContainer() {
+ if (isCommentTag()) {
+ CommentElementAdapter adapter = (CommentElementAdapter) getAdapterFor(CommentElementAdapter.class);
+ if (adapter != null) {
+ return (adapter.isContainer());
+ }
+ return (getDeclaration() == null);
+ }
+ if (isJSPTag()) {
+ // exclude JSP directive
+ return (matchTagName(JSPTag.JSP_SCRIPTLET) || matchTagName(JSPTag.JSP_DECLARATION) || matchTagName(JSPTag.JSP_EXPRESSION));
+ }
+ if (!isXMLTag()) { // non-XML tag
+ CMElementDeclaration decl = getDeclaration();
+ if (decl == null)
+ return false; // undefined tag
+ return (decl.getContentType() != CMElementDeclaration.EMPTY);
+ }
+ return true;
+ }
+
+ /**
+ * isEmptyTag method
+ *
+ * @return boolean
+ */
+ public boolean isEmptyTag() {
+ if (isJSPTag())
+ return false;
+ if (isCommentTag())
+ return false;
+ if (!isXMLTag())
+ return false;
+ return this.isEmptyTag;
+ }
+
+ /**
+ */
+ public boolean isEndTag() {
+ return (hasEndTag() && !hasStartTag() && !hasChildNodes());
+ }
+
+ /**
+ */
+ public boolean isGlobalTag() {
+ return !hasPrefix();
+ }
+
+ /**
+ */
+ public boolean isImplicitTag() {
+ if (hasStartTag() || hasEndTag())
+ return false;
+ // make sure this is in the document tree
+ // because if not in the document tree, no tags are generated yet
+ return (getContainerDocument() != null);
+ }
+
+ /**
+ */
+ public boolean isJSPContainer() {
+ return (isJSPTag() && !isCommentTag() && isContainer());
+ }
+
+ /**
+ * isJSPTag method
+ *
+ * @return boolean
+ */
+ public final boolean isJSPTag() {
+ return this.isJSPTag;
+ }
+
+ /**
+ */
+ public boolean isStartTagClosed() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return true; // will be generated
+ String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode);
+ if (isCommentTag()) {
+ return (regionType == XMLJSPRegionContexts.JSP_COMMENT_CLOSE || regionType == XMLRegionContext.XML_COMMENT_CLOSE);
+ }
+ if (isJSPTag()) {
+ if (isContainer())
+ return true; // start tag always has a single region
+ return (regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE);
+ }
+ return (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == XMLRegionContext.XML_DECLARATION_CLOSE);
+ }
+
+ /**
+ */
+ public final boolean isXMLTag() {
+ if (isJSPTag())
+ return false;
+ if (isCommentTag())
+ return false;
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document != null && !document.isXMLType()) {
+ // even in non-XML document, if having prefix, it's XML tag
+ return hasPrefix();
+ }
+ return true;
+ }
+
+ /**
+ */
+ protected boolean matchEndTag(Element element) {
+ if (element == null)
+ return false;
+ ElementImpl impl = (ElementImpl) element;
+ if (isJSPTag() && !isCommentTag()) {
+ return (impl.isJSPTag() && !impl.isCommentTag());
+ }
+ return matchTagName(element.getTagName());
+ }
+
+ /**
+ * matchTagName method
+ *
+ * @return boolean
+ * @param tagName
+ * java.lang.String
+ */
+ public boolean matchTagName(String tagName) {
+ if (tagName == null)
+ return (this.tagName == null);
+ if (this.tagName == null)
+ return false;
+ if (!ignoreCase())
+ return this.tagName.equals(tagName);
+ return this.tagName.equalsIgnoreCase(tagName);
+ }
+
+ /**
+ * notifyAttrReplaced method
+ *
+ * @param newAttr
+ * org.w3c.dom.Attr
+ * @param oldAttr
+ * org.w3c.dom.Attr
+ */
+ protected void notifyAttrReplaced(Attr newAttr, Attr oldAttr) {
+ DocumentImpl document = (DocumentImpl) getContainerDocument();
+ if (document == null)
+ return;
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.attrReplaced(this, newAttr, oldAttr);
+ }
+
+ /**
+ * notifyValueChanged method
+ */
+ public void notifyEndTagChanged() {
+ DocumentImpl document = (DocumentImpl) getContainerDocument();
+ if (document == null)
+ return;
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.endTagChanged(this);
+ }
+
+ /**
+ */
+ public void notifyStartTagChanged() {
+ DocumentImpl document = (DocumentImpl) getContainerDocument();
+ if (document == null)
+ return;
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.startTagChanged(this);
+ }
+
+ /**
+ */
+ public boolean preferEmptyTag() {
+ if (hasChildNodes())
+ return false;
+ if (isJSPTag())
+ return false;
+ if (isCommentTag())
+ return false;
+ if (!isXMLTag())
+ return false;
+ CMElementDeclaration decl = getDeclaration();
+ if (decl == null)
+ return false;
+ return (decl.getContentType() == CMElementDeclaration.EMPTY);
+ }
+
+ /**
+ * removeAttribute method
+ *
+ * @param name
+ * java.lang.String
+ */
+ public void removeAttribute(String name) throws DOMException {
+ removeAttributeNode(name);
+ }
+
+ /**
+ * removeAttributeNode method
+ *
+ * @return org.w3c.dom.Attr
+ * @param oldAttr
+ * org.w3c.dom.Attr
+ */
+ public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
+ if (oldAttr == null)
+ return null; // invalid parameter
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ if (this.attrNodes == null) { // no attribute
+ throw new DOMException(DOMException.NOT_FOUND_ERR, new String());
+ }
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr != oldAttr)
+ continue;
+
+ // found
+ this.attrNodes.removeNode(i);
+ attr.setOwnerElement(null);
+
+ notifyAttrReplaced(null, attr);
+ return attr;
+ }
+
+ // not found
+ throw new DOMException(DOMException.NOT_FOUND_ERR, new String());
+ }
+
+ /**
+ * removeAttributeNode method
+ *
+ * @return org.w3c.dom.Attr
+ * @param name
+ * java.lang.String
+ */
+ public Attr removeAttributeNode(String name) {
+ if (name == null)
+ return null; // invalid parameter
+ if (this.attrNodes == null)
+ return null; // no attribute
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr == null)
+ continue;
+ if (!attr.matchName(name))
+ continue;
+
+ // found
+ this.attrNodes.removeNode(i);
+ attr.setOwnerElement(null);
+
+ notifyAttrReplaced(null, attr);
+ return attr;
+ }
+
+ return null; // not found
+ }
+
+ /**
+ */
+ public Attr removeAttributeNodeNS(String uri, String name) {
+ if (name == null)
+ return null; // invalid parameter
+ if (this.attrNodes == null)
+ return null; // no attribute
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr == null)
+ continue;
+ String localName = attr.getLocalName();
+ if (localName == null || !localName.equals(name))
+ continue;
+ String nsURI = attr.getNamespaceURI();
+ if (uri == null) {
+ if (nsURI != null)
+ continue;
+ } else {
+ if (nsURI == null || !nsURI.equals(uri))
+ continue;
+ }
+
+ // found
+ this.attrNodes.removeNode(i);
+ attr.setOwnerElement(null);
+
+ notifyAttrReplaced(null, attr);
+ return attr;
+ }
+
+ return null; // not found
+ }
+
+ /**
+ */
+ public void removeAttributeNS(String uri, String name) throws DOMException {
+ removeAttributeNodeNS(uri, name);
+ }
+
+ /**
+ * removeAttributes method
+ */
+ public void removeAttributes() {
+ if (this.attrNodes == null)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr != null) {
+ attr.setOwnerElement(null);
+ notifyAttrReplaced(null, attr);
+ }
+ }
+
+ this.attrNodes = null;
+ }
+
+ /**
+ * removeEndTag method
+ *
+ * @return org.w3c.dom.Element
+ */
+ protected Element removeEndTag() {
+ if (!hasEndTag())
+ return null;
+ NodeListImpl attrNodes = this.attrNodes;
+ this.attrNodes = null; // not to copy attributes
+ ElementImpl end = (ElementImpl) cloneNode(false);
+ this.attrNodes = attrNodes;
+ if (end == null)
+ return null;
+
+ // move the end flat node to the end tag
+ IStructuredDocumentRegion flatNode = getEndStructuredDocumentRegion();
+ if (flatNode == null)
+ return null;
+ setEndStructuredDocumentRegion(null);
+ end.setEndStructuredDocumentRegion(flatNode);
+ return end;
+ }
+
+ /**
+ */
+ protected void removeStartTag() {
+ removeAttributes();
+ }
+
+ /**
+ * Resets attribute values from IStructuredDocumentRegion.
+ */
+ void resetStructuredDocumentRegions() {
+ if (this.attrNodes != null) {
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr == null)
+ continue;
+ attr.resetRegions();
+ }
+ }
+
+ super.resetStructuredDocumentRegions(); // for children
+
+ this.endStructuredDocumentRegion = null;
+ }
+
+ /**
+ * setAttribute method
+ *
+ * @param name
+ * java.lang.String
+ * @param value
+ * java.lang.String
+ */
+ public void setAttribute(String name, String value) throws DOMException {
+ if (name == null)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ Attr attr = getAttributeNode(name);
+ if (attr != null) {
+ attr.setValue(value); // change value
+ return;
+ }
+
+ // new attribute
+ Document doc = getOwnerDocument();
+ if (doc == null)
+ return;
+ attr = doc.createAttribute(name);
+ if (attr == null)
+ return;
+ attr.setValue(value);
+ appendAttributeNode(attr);
+ }
+
+ /**
+ * setAttributeNode method
+ *
+ * @return org.w3c.dom.Attr
+ * @param newAttr
+ * org.w3c.dom.Attr
+ */
+ public Attr setAttributeNode(Attr newAttr) throws DOMException {
+ if (newAttr == null)
+ return null; // nothing to do
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ AttrImpl attr = (AttrImpl) newAttr;
+ Element owner = attr.getOwnerElement();
+ if (owner != null) {
+ if (owner == this)
+ return null; // nothing to do
+ throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, new String());
+ }
+
+ Attr oldAttr = removeAttributeNode(newAttr.getName());
+ appendAttributeNode(attr);
+ return oldAttr;
+ }
+
+ /**
+ */
+ public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
+ if (newAttr == null)
+ return null; // nothing to do
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ AttrImpl attr = (AttrImpl) newAttr;
+ Element owner = attr.getOwnerElement();
+ if (owner != null) {
+ if (owner == this)
+ return null; // nothing to do
+ throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, new String());
+ }
+
+ String name = newAttr.getLocalName();
+ String uri = newAttr.getNamespaceURI();
+ Attr oldAttr = removeAttributeNodeNS(uri, name);
+ appendAttributeNode(attr);
+ return oldAttr;
+ }
+
+ /**
+ */
+ public void setAttributeNS(String uri, String name, String value) throws DOMException {
+ if (name == null)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ Attr attr = getAttributeNodeNS(uri, name);
+ if (attr != null) {
+ attr.setValue(value); // change value
+ return;
+ }
+
+ // new attribute
+ Document doc = getOwnerDocument();
+ if (doc == null)
+ return;
+ attr = doc.createAttributeNS(uri, name);
+ if (attr == null)
+ return;
+ attr.setValue(value);
+ appendAttributeNode(attr);
+ }
+
+ /**
+ */
+ public void setCommentTag(boolean isCommentTag) {
+ XMLNode parent = (XMLNode) getParentNode();
+ if (parent != null && !parent.isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.isCommentTag = isCommentTag;
+ }
+
+ /**
+ * setEmptyTag method
+ *
+ * @param isEmptyTag
+ * boolean
+ */
+ public void setEmptyTag(boolean isEmptyTag) {
+ XMLNode parent = (XMLNode) getParentNode();
+ if (parent != null && !parent.isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.isEmptyTag = isEmptyTag;
+ }
+
+ /**
+ * setEndStructuredDocumentRegion method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ void setEndStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ this.endStructuredDocumentRegion = flatNode;
+
+ NodeContainer parent = (NodeContainer) getParentNode();
+ if (parent != null) {
+ parent.syncChildEditableState(this);
+ }
+ }
+
+ /**
+ * setJSPTag method
+ *
+ * @param isJSPTag
+ * boolean
+ */
+ public void setJSPTag(boolean isJSPTag) {
+ XMLNode parent = (XMLNode) getParentNode();
+ if (parent != null && !parent.isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.isJSPTag = isJSPTag;
+ }
+
+ /**
+ */
+ protected void setNamespaceURI(String namespaceURI) {
+ this.namespaceURI = namespaceURI;
+ }
+
+ /**
+ */
+ protected void setOwnerDocument(Document ownerDocument, boolean deep) {
+ super.setOwnerDocument(ownerDocument, deep);
+
+ if (this.attrNodes == null)
+ return;
+
+ int length = this.attrNodes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) this.attrNodes.item(i);
+ if (attr == null)
+ continue;
+ attr.setOwnerDocument(ownerDocument);
+ }
+ }
+
+ /**
+ */
+ public void setPrefix(String prefix) throws DOMException {
+ XMLNode parent = (XMLNode) getParentNode();
+ if (parent != null && !parent.isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ int prefixLength = (prefix != null ? prefix.length() : 0);
+ String localName = getLocalName();
+ if (prefixLength == 0) {
+ if (localName == null || localName.length() == 0) {
+ // invalid local name
+ return;
+ }
+ setTagName(localName);
+ } else {
+ int localLength = (localName != null ? localName.length() : 0);
+ StringBuffer buffer = new StringBuffer(prefixLength + 1 + localLength);
+ buffer.append(prefix);
+ buffer.append(':');
+ if (localName != null)
+ buffer.append(localName);
+ setTagName(buffer.toString());
+ }
+
+ boolean changeEndTag = hasEndTag();
+ notifyStartTagChanged();
+ if (changeEndTag)
+ notifyEndTagChanged();
+ }
+
+ /**
+ * setStartStructuredDocumentRegion method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ void setStartStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ setStructuredDocumentRegion(flatNode);
+ }
+
+ /**
+ * setTagName method
+ *
+ * @param tagName
+ * java.lang.String
+ */
+ protected void setTagName(String tagName) {
+ this.tagName = tagName;
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ String tagName = getTagName();
+ if (hasStartTag())
+ buffer.append(tagName);
+ if (isEmptyTag())
+ buffer.append('/');
+ if (hasEndTag()) {
+ buffer.append('/');
+ buffer.append(tagName);
+ }
+ if (buffer.length() == 0)
+ buffer.append(tagName);
+
+ IStructuredDocumentRegion startStructuredDocumentRegion = getStartStructuredDocumentRegion();
+ if (startStructuredDocumentRegion != null) {
+ buffer.append('@');
+ buffer.append(startStructuredDocumentRegion.toString());
+ }
+ IStructuredDocumentRegion endStructuredDocumentRegion = getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null) {
+ buffer.append('@');
+ buffer.append(endStructuredDocumentRegion.toString());
+ }
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java
new file mode 100644
index 0000000000..80e5d6fdbd
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Entity;
+import org.w3c.dom.Node;
+
+/**
+ * EntityImpl class
+ */
+public class EntityImpl extends NodeImpl implements Entity {
+
+ private String name = null;
+ private String notationName = null;
+ private String publicId = null;
+ private String systemId = null;
+
+ /**
+ * EntityImpl constructor
+ */
+ protected EntityImpl() {
+ super();
+ }
+
+ /**
+ * EntityImpl constructor
+ *
+ * @param that
+ * EntityImpl
+ */
+ protected EntityImpl(EntityImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.name = that.name;
+ this.publicId = that.publicId;
+ this.systemId = that.systemId;
+ this.notationName = that.notationName;
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ EntityImpl cloned = new EntityImpl(this);
+ return cloned;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the text declaration, the encoding
+ * of this entity, when it is an external parsed entity. This is
+ * <code>null</code> otherwise.
+ *
+ * @since DOM Level 3
+ */
+ public java.lang.String getEncoding() {
+ return null;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ if (this.name == null)
+ return new String();
+ return this.name;
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return ENTITY_NODE;
+ }
+
+ /**
+ * getNotationName method
+ *
+ * @return java.lang.String
+ */
+ public String getNotationName() {
+ return this.notationName;
+ }
+
+ /**
+ * getPublicId method
+ *
+ * @return java.lang.String
+ */
+ public String getPublicId() {
+ return this.publicId;
+ }
+
+ /**
+ * getSystemId method
+ *
+ * @return java.lang.String
+ */
+ public String getSystemId() {
+ return this.systemId;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the text declaration, the version
+ * number of this entity, when it is an external parsed entity. This is
+ * <code>null</code> otherwise.
+ *
+ * @since DOM Level 3
+ */
+ public java.lang.String getVersion() {
+ return null;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the text declaration, the encoding
+ * of this entity, when it is an external parsed entity. This is
+ * <code>null</code> otherwise.
+ *
+ * @since DOM Level 3
+ */
+ public void setEncoding(java.lang.String encoding) {
+ }
+
+ /**
+ * setName method
+ *
+ * @param name
+ * java.lang.String
+ */
+ protected void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * setNotationName method
+ *
+ * @param notationName
+ * java.lang.String
+ */
+ public void setNotationName(String notationName) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.notationName = notationName;
+ }
+
+ /**
+ * setPublicId method
+ *
+ * @param publicId
+ * java.lang.String
+ */
+ public void setPublicId(String publicId) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.publicId = publicId;
+ }
+
+ /**
+ * setSystemId method
+ *
+ * @param systemId
+ * java.lang.String
+ */
+ public void setSystemId(String systemId) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.systemId = systemId;
+ }
+
+ /**
+ * <p>
+ * EXPERIMENTAL! Based on the <a
+ * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document
+ * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>.
+ * <p>
+ * An attribute specifying, as part of the text declaration, the version
+ * number of this entity, when it is an external parsed entity. This is
+ * <code>null</code> otherwise.
+ *
+ * @since DOM Level 3
+ */
+ public void setVersion(java.lang.String version) {
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java
new file mode 100644
index 0000000000..366ecc0dbd
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Node;
+
+/**
+ * EntityReference class
+ */
+public class EntityReferenceImpl extends NodeImpl implements EntityReference {
+
+ private String name = null;
+
+ /**
+ * EntityReferenceImpl constructor
+ */
+ protected EntityReferenceImpl() {
+ super();
+ }
+
+ /**
+ * EntityReferenceImpl constructor
+ *
+ * @param that
+ * EntityReferenceImpl
+ */
+ protected EntityReferenceImpl(EntityReferenceImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.name = that.name;
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ EntityReferenceImpl cloned = new EntityReferenceImpl(this);
+ return cloned;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ if (this.name == null)
+ return new String();
+ return this.name;
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return ENTITY_REFERENCE_NODE;
+ }
+
+ /**
+ * setName method
+ *
+ * @param name
+ * java.lang.String
+ */
+ protected void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java
new file mode 100644
index 0000000000..011079bc31
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.INodeAdapter;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ */
+public interface ModelParserAdapter extends INodeAdapter {
+
+ /**
+ */
+ public boolean canBeImplicitTag(Element element);
+
+ /**
+ */
+ public boolean canBeImplicitTag(Element element, Node child);
+
+ /**
+ */
+ public boolean canContain(Element element, Node child);
+
+ /**
+ */
+ public Element createCommentElement(Document document, String data, boolean isJSPTag);
+
+ /**
+ */
+ public Element createImplicitElement(Document document, Node parent, Node child);
+
+ /**
+ */
+ public String getFindRootName(String tagName);
+
+ /**
+ */
+ public boolean isEndTag(XMLElement element);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java
new file mode 100644
index 0000000000..121d57cb17
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java
@@ -0,0 +1,514 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+/**
+ * NodeContainer class
+ */
+public abstract class NodeContainer extends NodeImpl implements Node, NodeList {
+
+ /**
+ */
+ private class ChildNodesCache implements NodeList {
+ private Node curChild = null;
+ private int curIndex = -1;
+ private int length = 0;
+
+ ChildNodesCache() {
+ initializeCache();
+ }
+
+ public int getLength() {
+ // atomic
+ return this.length;
+ }
+
+ private void initializeCache() {
+ // note we use the outter objects lockobject
+ // (since we are using their "children".
+ synchronized (lockObject) {
+ for (Node child = firstChild; child != null; child = child.getNextSibling()) {
+ this.length++;
+ }
+ }
+ }
+
+ public Node item(int index) {
+ synchronized (lockObject) {
+ if (this.length == 0)
+ return null;
+ if (index < 0)
+ return null;
+ if (index >= this.length)
+ return null;
+
+ if (this.curIndex < 0) { // first time
+ if (index * 2 >= this.length) { // search from the last
+ this.curIndex = this.length - 1;
+ this.curChild = lastChild;
+ } else { // search from the first
+ this.curIndex = 0;
+ this.curChild = firstChild;
+ }
+ }
+
+ if (index == this.curIndex)
+ return this.curChild;
+
+ if (index > this.curIndex) {
+ while (index > this.curIndex) {
+ this.curIndex++;
+ this.curChild = this.curChild.getNextSibling();
+ }
+ } else { // index < this.curIndex
+ while (index < this.curIndex) {
+ this.curIndex--;
+ this.curChild = this.curChild.getPreviousSibling();
+ }
+ }
+
+ return this.curChild;
+ }
+ }
+ }
+
+ private NodeList childNodesCache = null;
+
+ private boolean fChildEditable = true;
+ NodeImpl firstChild = null;
+ NodeImpl lastChild = null;
+
+ Object lockObject = new byte[0];
+
+ /**
+ * NodeContainer constructor
+ */
+ protected NodeContainer() {
+ super();
+ }
+
+ /**
+ * NodeContainer constructor
+ *
+ * @param that
+ * NodeContainer
+ */
+ protected NodeContainer(NodeContainer that) {
+ super(that);
+ }
+
+ /**
+ * appendChild method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ */
+ public Node appendChild(Node newChild) throws DOMException {
+ return insertBefore(newChild, null);
+ }
+
+ /**
+ * cloneChildNodes method
+ *
+ * @param container
+ * org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ protected void cloneChildNodes(Node newParent, boolean deep) {
+ if (newParent == null || newParent == this)
+ return;
+ if (!(newParent instanceof NodeContainer))
+ return;
+
+ NodeContainer container = (NodeContainer) newParent;
+ container.removeChildNodes();
+
+ for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) {
+ Node cloned = child.cloneNode(deep);
+ if (cloned != null)
+ container.appendChild(cloned);
+ }
+ }
+
+ /**
+ * getChildNodes method
+ *
+ * @return org.w3c.dom.NodeList
+ */
+ public NodeList getChildNodes() {
+ return this;
+ }
+
+ /**
+ * getFirstChild method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getFirstChild() {
+ return this.firstChild;
+ }
+
+ /**
+ * getLastChild method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getLastChild() {
+ return this.lastChild;
+ }
+
+ /**
+ * getLength method
+ *
+ * @return int
+ */
+ public int getLength() {
+ if (this.firstChild == null)
+ return 0;
+ synchronized (lockObject) {
+ if (this.childNodesCache == null)
+ this.childNodesCache = new ChildNodesCache();
+ return this.childNodesCache.getLength();
+ }
+ }
+
+ /**
+ */
+ public String getSource() {
+ StringBuffer buffer = new StringBuffer();
+
+ IStructuredDocumentRegion startStructuredDocumentRegion = getStartStructuredDocumentRegion();
+ if (startStructuredDocumentRegion != null) {
+ String source = startStructuredDocumentRegion.getText();
+ if (source != null)
+ buffer.append(source);
+ }
+
+ for (NodeImpl child = firstChild; child != null; child = (NodeImpl) child.getNextSibling()) {
+ String source = child.getSource();
+ if (source != null)
+ buffer.append(source);
+ }
+
+ IStructuredDocumentRegion endStructuredDocumentRegion = getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null) {
+ String source = endStructuredDocumentRegion.getText();
+ if (source != null)
+ buffer.append(source);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * hasChildNodes method
+ *
+ * @return boolean
+ */
+ public boolean hasChildNodes() {
+ return (this.firstChild != null);
+ }
+
+ /**
+ * insertBefore method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param refChild
+ * org.w3c.dom.Node
+ */
+ public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+ if (newChild == null)
+ return null; // nothing to do
+ if (refChild != null && refChild.getParentNode() != this) {
+ throw new DOMException(DOMException.NOT_FOUND_ERR, new String());
+ }
+ if (!isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ if (newChild == refChild)
+ return newChild; // nothing to do
+
+ if (newChild.getNodeType() == DOCUMENT_FRAGMENT_NODE) {
+ // insert child nodes instead
+ for (Node child = newChild.getFirstChild(); child != null; child = newChild.getFirstChild()) {
+ newChild.removeChild(child);
+ insertBefore(child, refChild);
+ }
+ return newChild;
+ }
+ // synchronized in case another thread is getting item, or length
+ synchronized (lockObject) {
+ this.childNodesCache = null; // invalidate child nodes cache
+ }
+
+ NodeImpl child = (NodeImpl) newChild;
+ NodeImpl next = (NodeImpl) refChild;
+ NodeImpl prev = null;
+ Node oldParent = child.getParentNode();
+ if (oldParent != null)
+ oldParent.removeChild(child);
+ if (next == null) {
+ prev = this.lastChild;
+ this.lastChild = child;
+ } else {
+ prev = (NodeImpl) next.getPreviousSibling();
+ next.setPreviousSibling(child);
+ }
+ if (prev == null)
+ this.firstChild = child;
+ else
+ prev.setNextSibling(child);
+ child.setPreviousSibling(prev);
+ child.setNextSibling(next);
+ child.setParentNode(this);
+ // make sure having the same owner document
+ if (child.getOwnerDocument() == null) {
+ if (getNodeType() == DOCUMENT_NODE) {
+ child.setOwnerDocument((Document) this);
+ } else {
+ child.setOwnerDocument(getOwnerDocument());
+ }
+ }
+
+ notifyChildReplaced(child, null);
+
+ return child;
+ }
+
+ public boolean isChildEditable() {
+ if (!fChildEditable) {
+ XMLModelImpl model = (XMLModelImpl) getModel();
+ if (model != null && model.isReparsing()) {
+ return true;
+ }
+ }
+ return fChildEditable;
+ }
+
+ /**
+ * isContainer method
+ *
+ * @return boolean
+ */
+ public boolean isContainer() {
+ return true;
+ }
+
+ /**
+ * item method
+ *
+ * @return org.w3c.dom.Node
+ * @param index
+ * int
+ */
+ public Node item(int index) {
+ if (this.firstChild == null)
+ return null;
+ synchronized (lockObject) {
+ if (this.childNodesCache == null)
+ this.childNodesCache = new ChildNodesCache();
+ return this.childNodesCache.item(index);
+ }
+ }
+
+ /**
+ * notifyChildReplaced method
+ *
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ protected void notifyChildReplaced(Node newChild, Node oldChild) {
+ DocumentImpl document = (DocumentImpl) getContainerDocument();
+ if (document == null)
+ return;
+
+ syncChildEditableState(newChild);
+
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.childReplaced(this, newChild, oldChild);
+ }
+
+ /**
+ * removeChild method
+ *
+ * @return org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ public Node removeChild(Node oldChild) throws DOMException {
+ if (oldChild == null)
+ return null;
+ if (oldChild.getParentNode() != this) {
+ throw new DOMException(DOMException.NOT_FOUND_ERR, new String());
+ }
+
+ if (!isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ // synchronized in case another thread is getting item, or length
+ synchronized (lockObject) {
+ this.childNodesCache = null; // invalidate child nodes cache
+ }
+
+ NodeImpl child = (NodeImpl) oldChild;
+ NodeImpl prev = (NodeImpl) child.getPreviousSibling();
+ NodeImpl next = (NodeImpl) child.getNextSibling();
+
+ child.setEditable(true, true); // clear ReadOnly flags
+
+ if (prev == null)
+ this.firstChild = next;
+ else
+ prev.setNextSibling(next);
+ if (next == null)
+ this.lastChild = prev;
+ else
+ next.setPreviousSibling(prev);
+ child.setPreviousSibling(null);
+ child.setNextSibling(null);
+ child.setParentNode(null);
+
+ notifyChildReplaced(null, child);
+
+ return child;
+ }
+
+ /**
+ * removeChildNodes method
+ */
+ public void removeChildNodes() {
+ if (!isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ Node nextChild = null;
+ for (Node child = getFirstChild(); child != null; child = nextChild) {
+ nextChild = child.getNextSibling();
+ removeChild(child);
+ }
+ }
+
+ /**
+ * removeChildNodes method
+ *
+ * @return org.w3c.dom.DocumentFragment
+ * @param firstChild
+ * org.w3c.dom.Node
+ * @param lastChild
+ * org.w3c.dom.Node
+ */
+ public DocumentFragment removeChildNodes(Node firstChild, Node lastChild) {
+ if (!hasChildNodes())
+ return null;
+ if (!isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ Document document = null;
+ if (getNodeType() == DOCUMENT_NODE)
+ document = (Document) this;
+ else
+ document = getOwnerDocument();
+ if (document == null)
+ return null;
+ DocumentFragment fragment = document.createDocumentFragment();
+ if (fragment == null)
+ return null;
+
+ if (firstChild == null)
+ firstChild = getFirstChild();
+ if (lastChild == null)
+ lastChild = getLastChild();
+ Node nextChild = null;
+ for (Node child = firstChild; child != null; child = nextChild) {
+ nextChild = child.getNextSibling();
+ removeChild(child);
+ fragment.appendChild(child);
+ if (child == lastChild)
+ break;
+ }
+
+ return fragment;
+ }
+
+ /**
+ * replaceChild method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+ if (!isChildEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ if (oldChild == null)
+ return newChild;
+ if (newChild != null)
+ insertBefore(newChild, oldChild);
+ return removeChild(oldChild);
+ }
+
+ public void setChildEditable(boolean editable) {
+ if (fChildEditable == editable) {
+ return;
+ }
+
+ ReadOnlyController roc = ReadOnlyController.getInstance();
+ Node node;
+ if (editable) {
+ for (node = getFirstChild(); node != null; node = node.getNextSibling()) {
+ roc.unlockNode((XMLNode) node);
+ }
+ } else {
+ for (node = getFirstChild(); node != null; node = node.getNextSibling()) {
+ roc.lockNode((XMLNode) node);
+ }
+ }
+
+ fChildEditable = editable;
+ notifyEditableChanged();
+ }
+
+ protected void syncChildEditableState(Node child) {
+ ReadOnlyController roc = ReadOnlyController.getInstance();
+ if (fChildEditable) {
+ roc.unlockNode((NodeImpl) child);
+ } else {
+ roc.lockNode((NodeImpl) child);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java
new file mode 100644
index 0000000000..0ea5dde799
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java
@@ -0,0 +1,809 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.AbstractNotifier;
+import org.eclipse.wst.sse.core.IFactoryRegistry;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.document.InvalidCharacterException;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+
+/**
+ * NodeImpl class
+ */
+public abstract class NodeImpl extends AbstractNotifier implements XMLNode {
+ // define one empty nodelist, for repeated use
+ private final static NodeList EMPTY_NODE_LIST = new NodeListImpl();
+
+ private boolean fDataEditable = true;
+ private IStructuredDocumentRegion flatNode = null;
+ private NodeImpl nextSibling = null;
+
+ private DocumentImpl ownerDocument = null;
+ private NodeImpl parentNode = null;
+ private NodeImpl previousSibling = null;
+
+ /**
+ * NodeImpl constructor
+ */
+ protected NodeImpl() {
+ super();
+ }
+
+ /**
+ * NodeImpl constructor
+ *
+ * @param that
+ * NodeImpl
+ */
+ protected NodeImpl(NodeImpl that) {
+ if (that != null) {
+ this.ownerDocument = that.ownerDocument;
+ }
+ }
+
+ /**
+ * appendChild method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ */
+ public Node appendChild(Node newChild) throws DOMException {
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String());
+ }
+
+ /**
+ * contains method
+ *
+ * @return boolean
+ * @param offset
+ * int
+ */
+ public boolean contains(int offset) {
+ return (offset >= getStartOffset() && offset < getEndOffset());
+ }
+
+ /**
+ * @param s
+ * @param tagName
+ * @return
+ */
+ protected String createDOMExceptionMessage(short s, String tagName) {
+ String result = null;
+ // TODO: Should localize these messages, and provide /u escaped
+ // version of tagName
+ result = lookupMessage(s) + " " + tagName; //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * getAttributes method
+ *
+ * @return org.w3c.dom.NamedNodeMap
+ */
+ public NamedNodeMap getAttributes() {
+ return null;
+ }
+
+ /**
+ */
+ protected String getCharValue(String name) {
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document == null)
+ return null;
+ return document.getCharValue(name);
+ }
+
+ /**
+ * getChildNodes method
+ *
+ * @return org.w3c.dom.NodeList
+ */
+ public NodeList getChildNodes() {
+ // As per DOM spec, correct behavior for getChildNodes is to return a
+ // zero length NodeList, not null, when there are no children.
+ // We'll use a common instance of an empty node list, just to prevent
+ // creating a trival object many many times.
+
+ return EMPTY_NODE_LIST;
+ }
+
+ /**
+ * getCommonAncestor method
+ *
+ * @return org.w3c.dom.Node
+ * @param node
+ * org.w3c.dom.Node
+ */
+ public Node getCommonAncestor(Node node) {
+ if (node == null)
+ return null;
+
+ for (Node na = node; na != null; na = na.getParentNode()) {
+ for (Node ta = this; ta != null; ta = ta.getParentNode()) {
+ if (ta == na)
+ return ta;
+ }
+ }
+
+ return null; // not found
+ }
+
+ /**
+ * getContainerDocument method
+ *
+ * @return org.w3c.dom.Document
+ */
+ public Document getContainerDocument() {
+ for (Node node = this; node != null; node = node.getParentNode()) {
+ if (node.getNodeType() == Node.DOCUMENT_NODE) {
+ return (Document) node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * getEndOffset method
+ *
+ * @return int
+ */
+ public int getEndOffset() {
+ Node node = this;
+ while (node != null) {
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) node;
+ IStructuredDocumentRegion endStructuredDocumentRegion = element.getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null)
+ return endStructuredDocumentRegion.getEnd();
+ }
+
+ Node last = node.getLastChild();
+ if (last != null) { // dig into the last
+ node = last;
+ continue;
+ }
+
+ IStructuredDocumentRegion lastStructuredDocumentRegion = ((NodeImpl) node).getStructuredDocumentRegion();
+ if (lastStructuredDocumentRegion != null)
+ return lastStructuredDocumentRegion.getEnd();
+
+ Node prev = node.getPreviousSibling();
+ if (prev != null) { // move to the previous
+ node = prev;
+ continue;
+ }
+
+ Node parent = node.getParentNode();
+ node = null;
+ while (parent != null) {
+ if (parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) parent;
+ IStructuredDocumentRegion startStructuredDocumentRegion = element.getStartStructuredDocumentRegion();
+ if (startStructuredDocumentRegion != null)
+ return startStructuredDocumentRegion.getEnd();
+ }
+ Node parentPrev = parent.getPreviousSibling();
+ if (parentPrev != null) { // move to the previous
+ node = parentPrev;
+ break;
+ }
+ parent = parent.getParentNode();
+ }
+ }
+ return 0;
+ }
+
+ public IStructuredDocumentRegion getEndStructuredDocumentRegion() {
+ return null;
+ }
+
+ /**
+ */
+ public IFactoryRegistry getFactoryRegistry() {
+ XMLModel model = getModel();
+ if (model != null) {
+ IFactoryRegistry reg = model.getFactoryRegistry();
+ if (reg != null)
+ return reg;
+ }
+ return null;
+ }
+
+ /**
+ * getFirstChild method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getFirstChild() {
+ return null;
+ }
+
+ /**
+ * getFirstStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getFirstStructuredDocumentRegion() {
+ return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.flatNode);
+ }
+
+ /**
+ */
+ public int getIndex() {
+ Node parent = getParentNode();
+ if (parent == null)
+ return -1; // error
+ int index = 0;
+ for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child == this)
+ return index;
+ index++;
+ }
+ return -1; // error
+ }
+
+ /**
+ * getLastChild method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getLastChild() {
+ return null;
+ }
+
+ /**
+ * getLastStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getLastStructuredDocumentRegion() {
+ return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.flatNode);
+ }
+
+ /**
+ */
+ public String getLocalName() {
+ return null;
+ }
+
+ /**
+ * the default implementation can just refer to the owning document
+ */
+ public XMLModel getModel() {
+ if (this.ownerDocument == null)
+ return null;
+ return this.ownerDocument.getModel();
+ }
+
+ /**
+ * all but attr return null
+ */
+ public ITextRegion getNameRegion() {
+ return null;
+ }
+
+ /**
+ */
+ public String getNamespaceURI() {
+ return null;
+ }
+
+ /**
+ * getNextSibling method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getNextSibling() {
+ return this.nextSibling;
+ }
+
+ /**
+ * getNodeAt method
+ *
+ * @return org.w3c.dom.Node
+ * @param offset
+ * int
+ */
+ Node getNodeAt(int offset) {
+ XMLNode parent = this;
+ XMLNode child = (XMLNode) getFirstChild();
+ while (child != null) {
+ if (child.getEndOffset() <= offset) {
+ child = (XMLNode) child.getNextSibling();
+ continue;
+ }
+ if (child.getStartOffset() > offset) {
+ break;
+ }
+
+ IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
+ if (startStructuredDocumentRegion != null) {
+ if (startStructuredDocumentRegion.getEnd() > offset)
+ return child;
+ }
+
+ // dig more
+ parent = child;
+ child = (XMLNode) parent.getFirstChild();
+ }
+
+ return parent;
+ }
+
+ /**
+ * getNodeValue method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeValue() throws DOMException {
+ return null;
+ }
+
+ /**
+ * getOwnerDocument method
+ *
+ * @return org.w3c.dom.Document
+ */
+ public Document getOwnerDocument() {
+ return this.ownerDocument;
+ }
+
+ /**
+ * getParentNode method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getParentNode() {
+ return this.parentNode;
+ }
+
+ /**
+ */
+ public String getPrefix() {
+ return null;
+ }
+
+ /**
+ * getPreviousSibling method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node getPreviousSibling() {
+ return this.previousSibling;
+ }
+
+ /**
+ */
+ public String getSource() {
+ if (this.flatNode == null)
+ return new String();
+ return this.flatNode.getText();
+ }
+
+ /**
+ * getStartOffset method
+ *
+ * @return int
+ */
+ public int getStartOffset() {
+ if (this.flatNode != null)
+ return this.flatNode.getStart();
+ NodeImpl prev = (NodeImpl) getPreviousSibling();
+ if (prev != null)
+ return prev.getEndOffset();
+ Node parent = getParentNode();
+ if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) parent;
+ if (element.hasStartTag())
+ return element.getStartEndOffset();
+ return element.getStartOffset();
+ }
+ // final fallback to look into first child
+ NodeImpl child = (NodeImpl) getFirstChild();
+ while (child != null) {
+ IStructuredDocumentRegion childStructuredDocumentRegion = child.getStructuredDocumentRegion();
+ if (childStructuredDocumentRegion != null)
+ return childStructuredDocumentRegion.getStart();
+ child = (NodeImpl) child.getFirstChild();
+ }
+ return 0;
+ }
+
+ public IStructuredDocumentRegion getStartStructuredDocumentRegion() {
+ return getFirstStructuredDocumentRegion();
+ }
+
+ /**
+ * Every node (indirectly) knows its structuredDocument
+ */
+ public IStructuredDocument getStructuredDocument() {
+ return getModel().getStructuredDocument();
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion getStructuredDocumentRegion() {
+ return this.flatNode;
+ }
+
+ /**
+ * all but attr return null
+ */
+ public ITextRegion getValueRegion() {
+ return null;
+ }
+
+ /**
+ */
+ public String getValueSource() {
+ return getNodeValue();
+ }
+
+ /**
+ */
+ public boolean hasAttributes() {
+ return false;
+ }
+
+ /**
+ * hasChildNodes method
+ *
+ * @return boolean
+ */
+ public boolean hasChildNodes() {
+ return false;
+ }
+
+ /**
+ * hasProperties method
+ *
+ * @return boolean
+ */
+ public boolean hasProperties() {
+ return false;
+ }
+
+ /**
+ * insertBefore method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param refChild
+ * org.w3c.dom.Node
+ */
+ public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String());
+ }
+
+ public boolean isChildEditable() {
+ return false;
+ }
+
+ /**
+ */
+ public boolean isClosed() {
+ return true;
+ }
+
+ /**
+ * isContainer method
+ *
+ * @return boolean
+ */
+ public boolean isContainer() {
+ return false;
+ }
+
+ public boolean isDataEditable() {
+ if (!fDataEditable) {
+ XMLModelImpl model = (XMLModelImpl) getModel();
+ if (model != null && model.isReparsing()) {
+ return true;
+ }
+ }
+ return fDataEditable;
+ }
+
+ /**
+ */
+ public boolean isSupported(String feature, String version) {
+ if (this.ownerDocument == null)
+ return false;
+ DOMImplementation impl = this.ownerDocument.getImplementation();
+ if (impl == null)
+ return false;
+ return impl.hasFeature(feature, version);
+ }
+
+ /**
+ * @param s
+ * @return
+ */
+ private String lookupMessage(short s) {
+ // TODO: make localized version
+ String result = null;
+ switch (s) {
+ case DOMException.INVALID_CHARACTER_ERR :
+ result = "INVALID_CHARACTER_ERR"; //$NON-NLS-1$
+ break;
+
+ default :
+ result = new String();
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * normalize method
+ */
+ public void normalize() {
+ TextImpl prevText = null;
+ for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) {
+ switch (child.getNodeType()) {
+ case TEXT_NODE : {
+ if (prevText == null) {
+ prevText = (TextImpl) child;
+ break;
+ }
+ Text text = (Text) child;
+ removeChild(text);
+ prevText.appendText(text);
+ child = prevText;
+ break;
+ }
+ case ELEMENT_NODE : {
+ Element element = (Element) child;
+ element.normalize();
+ prevText = null;
+ break;
+ }
+ default :
+ prevText = null;
+ break;
+ }
+ }
+ }
+
+ protected void notifyEditableChanged() {
+ DocumentImpl document = (DocumentImpl) getContainerDocument();
+ if (document == null)
+ return;
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.editableChanged(this);
+ }
+
+ /**
+ * notifyValueChanged method
+ */
+ protected void notifyValueChanged() {
+ DocumentImpl document = (DocumentImpl) getContainerDocument();
+ if (document == null)
+ return;
+
+ syncDataEditableState();
+
+ XMLModelImpl model = (XMLModelImpl) document.getModel();
+ if (model == null)
+ return;
+ model.valueChanged(this);
+ }
+
+ /**
+ * removeChild method
+ *
+ * @return org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ public Node removeChild(Node oldChild) throws DOMException {
+ throw new DOMException(DOMException.NOT_FOUND_ERR, new String());
+ }
+
+ /**
+ * removeChildNodes method
+ */
+ public void removeChildNodes() {
+ }
+
+ /**
+ * removeChildNodes method
+ *
+ * @return org.w3c.dom.DocumentFragment
+ * @param firstChild
+ * org.w3c.dom.Node
+ * @param lastChild
+ * org.w3c.dom.Node
+ */
+ public DocumentFragment removeChildNodes(Node firstChild, Node lastChild) {
+ return null;
+ }
+
+ /**
+ * replaceChild method
+ *
+ * @return org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+ throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String());
+ }
+
+ /**
+ * Resets children values from IStructuredDocumentRegion.
+ */
+ void resetStructuredDocumentRegions() {
+ for (NodeImpl child = (NodeImpl) getFirstChild(); child != null; child = (NodeImpl) child.getNextSibling()) {
+ child.resetStructuredDocumentRegions();
+ }
+ this.flatNode = null;
+ }
+
+ public void setChildEditable(boolean editable) {
+ // nop
+ }
+
+ public void setDataEditable(boolean editable) {
+ if (fDataEditable == editable) {
+ return;
+ }
+
+ ReadOnlyController roc = ReadOnlyController.getInstance();
+ if (editable) {
+ roc.unlockData(this);
+ } else {
+ roc.lockData(this);
+ }
+
+ fDataEditable = editable;
+
+ notifyEditableChanged();
+ }
+
+ public void setEditable(boolean editable, boolean deep) {
+ if (deep) {
+ XMLNode node = (XMLNode) getFirstChild();
+ while (node != null) {
+ node.setEditable(editable, deep);
+ node = (XMLNode) node.getNextSibling();
+ }
+ }
+ setChildEditable(editable);
+ setDataEditable(editable);
+ }
+
+ /**
+ * setNextSibling method
+ *
+ * @param nextSibling
+ * org.w3c.dom.Node
+ */
+ protected void setNextSibling(Node nextSibling) {
+ this.nextSibling = (NodeImpl) nextSibling;
+ }
+
+ /**
+ * setNodeValue method
+ *
+ * @param nodeValue
+ * java.lang.String
+ */
+ public void setNodeValue(String nodeValue) throws DOMException {
+ }
+
+ /**
+ * setOwnerDocument method
+ *
+ * @param ownerDocument
+ * org.w3c.dom.Document
+ */
+ protected void setOwnerDocument(Document ownerDocument) {
+ this.ownerDocument = (DocumentImpl) ownerDocument;
+ }
+
+ /**
+ */
+ protected void setOwnerDocument(Document ownerDocument, boolean deep) {
+ this.ownerDocument = (DocumentImpl) ownerDocument;
+
+ if (deep) {
+ for (NodeImpl child = (NodeImpl) getFirstChild(); child != null; child = (NodeImpl) child.getNextSibling()) {
+ child.setOwnerDocument(ownerDocument, deep);
+ }
+ }
+ }
+
+ /**
+ * setParentNode method
+ *
+ * @param parentNode
+ * org.w3c.dom.Node
+ */
+ protected void setParentNode(Node parentNode) {
+ this.parentNode = (NodeImpl) parentNode;
+ }
+
+ /**
+ */
+ public void setPrefix(String prefix) throws DOMException {
+ }
+
+ /**
+ * setPreviousSibling method
+ *
+ * @param previousSibling
+ * org.w3c.dom.Node
+ */
+ protected void setPreviousSibling(Node previousSibling) {
+ this.previousSibling = (NodeImpl) previousSibling;
+ }
+
+ /**
+ */
+ public void setSource(String source) throws InvalidCharacterException {
+ // not supported
+ }
+
+ /**
+ */
+ void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ this.flatNode = flatNode;
+ }
+
+ /**
+ */
+ public void setValueSource(String source) {
+ setNodeValue(source);
+ }
+
+ protected void syncDataEditableState() {
+ ReadOnlyController roc = ReadOnlyController.getInstance();
+ if (fDataEditable) {
+ roc.unlockData(this);
+ } else {
+ roc.lockData(this);
+ }
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ return getNodeName();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java
new file mode 100644
index 0000000000..c4a278b694
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.NodeIterator;
+
+/**
+ * NodeIteratorImpl class
+ */
+public class NodeIteratorImpl implements NodeIterator {
+ private NodeFilter filter = null;
+ private Node nextNode = null;
+
+ private Node rootNode = null;
+ private int whatToShow = NodeFilter.SHOW_ALL;
+
+ /**
+ * NodeIteratorImpl constructor
+ *
+ * @param rootNode
+ * org.w3c.dom.Node
+ */
+ NodeIteratorImpl(Node rootNode, int whatToShow, NodeFilter filter) {
+ this.rootNode = rootNode;
+ this.nextNode = rootNode;
+ this.whatToShow = whatToShow;
+ this.filter = filter;
+ }
+
+ /**
+ */
+ private final boolean acceptNode(Node node) {
+ if (this.whatToShow != NodeFilter.SHOW_ALL) {
+ if (node == null)
+ return false;
+ short nodeType = node.getNodeType();
+ switch (this.whatToShow) {
+ case NodeFilter.SHOW_ELEMENT :
+ if (nodeType != Node.ELEMENT_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_ATTRIBUTE :
+ if (nodeType != Node.ATTRIBUTE_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_TEXT :
+ if (nodeType != Node.TEXT_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_CDATA_SECTION :
+ if (nodeType != Node.CDATA_SECTION_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_ENTITY_REFERENCE :
+ if (nodeType != Node.ENTITY_REFERENCE_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_ENTITY :
+ if (nodeType != Node.ENTITY_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_PROCESSING_INSTRUCTION :
+ if (nodeType != Node.PROCESSING_INSTRUCTION_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_COMMENT :
+ if (nodeType != Node.COMMENT_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_DOCUMENT :
+ if (nodeType != Node.DOCUMENT_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_DOCUMENT_TYPE :
+ if (nodeType != Node.DOCUMENT_TYPE_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_DOCUMENT_FRAGMENT :
+ if (nodeType != Node.DOCUMENT_FRAGMENT_NODE)
+ return false;
+ break;
+ case NodeFilter.SHOW_NOTATION :
+ if (nodeType != Node.NOTATION_NODE)
+ return false;
+ break;
+ default :
+ return false;
+ }
+ }
+ if (this.filter != null) {
+ return (this.filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT);
+ }
+ return true;
+ }
+
+ /**
+ * Detaches the <code>NodeIterator</code> from the set which it iterated
+ * over, releasing any computational resources and placing the iterator in
+ * the INVALID state. After <code>detach</code> has been invoked, calls
+ * to <code>nextNode</code> or <code>previousNode</code> will raise
+ * the exception INVALID_STATE_ERR.
+ */
+ public void detach() {
+ this.rootNode = null;
+ this.nextNode = null;
+ this.filter = null;
+ }
+
+ /**
+ * The value of this flag determines whether the children of entity
+ * reference nodes are visible to the iterator. If false, they and their
+ * descendants will be rejected. Note that this rejection takes precedence
+ * over <code>whatToShow</code> and the filter. Also note that this is
+ * currently the only situation where <code>NodeIterators</code> may
+ * reject a complete subtree rather than skipping individual nodes. <br>
+ * <br>
+ * To produce a view of the document that has entity references expanded
+ * and does not expose the entity reference node itself, use the
+ * <code>whatToShow</code> flags to hide the entity reference node and
+ * set <code>expandEntityReferences</code> to true when creating the
+ * iterator. To produce a view of the document that has entity reference
+ * nodes but no entity expansion, use the <code>whatToShow</code> flags
+ * to show the entity reference node and set
+ * <code>expandEntityReferences</code> to false.
+ */
+ public boolean getExpandEntityReferences() {
+ // not supported
+ return false;
+ }
+
+ /**
+ * The <code>NodeFilter</code> used to screen nodes.
+ */
+ public NodeFilter getFilter() {
+ return this.filter;
+ }
+
+ /**
+ */
+ private final Node getNextNode() {
+ if (this.nextNode == null)
+ return null;
+ Node oldNext = this.nextNode;
+ Node child = this.nextNode.getFirstChild();
+ if (child != null) {
+ this.nextNode = child;
+ return oldNext;
+ }
+ for (Node node = this.nextNode; node != null && node != this.rootNode; node = node.getParentNode()) {
+ Node next = node.getNextSibling();
+ if (next != null) {
+ this.nextNode = next;
+ return oldNext;
+ }
+ }
+ this.nextNode = null;
+ return oldNext;
+ }
+
+ /**
+ */
+ private final Node getPreviousNode() {
+ if (this.nextNode == this.rootNode)
+ return null;
+ Node prev = null;
+ if (this.nextNode == null) {
+ prev = this.rootNode; // never null
+ } else {
+ prev = this.nextNode.getPreviousSibling();
+ if (prev == null) {
+ this.nextNode = this.nextNode.getParentNode();
+ return this.nextNode;
+ }
+ }
+ Node last = prev.getLastChild();
+ while (last != null) {
+ prev = last;
+ last = prev.getLastChild();
+ }
+ this.nextNode = prev;
+ return this.nextNode;
+ }
+
+ /**
+ * The root node of the <code>NodeIterator</code>, as specified when it
+ * was created.
+ */
+ public Node getRoot() {
+ return this.rootNode;
+ }
+
+ /**
+ * This attribute determines which node types are presented via the
+ * iterator. The available set of constants is defined in the
+ * <code>NodeFilter</code> interface. Nodes not accepted by
+ * <code>whatToShow</code> will be skipped, but their children may still
+ * be considered. Note that this skip takes precedence over the filter, if
+ * any.
+ */
+ public int getWhatToShow() {
+ return this.whatToShow;
+ }
+
+ /**
+ * Returns the next node in the set and advances the position of the
+ * iterator in the set. After a <code>NodeIterator</code> is created,
+ * the first call to <code>nextNode()</code> returns the first node in
+ * the set.
+ *
+ * @return The next <code>Node</code> in the set being iterated over, or
+ * <code>null</code> if there are no more members in that set.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if this method is called after
+ * the <code>detach</code> method was invoked.
+ */
+ public Node nextNode() throws DOMException {
+ for (Node node = getNextNode(); node != null; node = getNextNode()) {
+ if (acceptNode(node))
+ return node;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the previous node in the set and moves the position of the
+ * <code>NodeIterator</code> backwards in the set.
+ *
+ * @return The previous <code>Node</code> in the set being iterated
+ * over, or <code>null</code> if there are no more members in
+ * that set.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if this method is called after
+ * the <code>detach</code> method was invoked.
+ */
+ public Node previousNode() throws DOMException {
+ for (Node node = getPreviousNode(); node != null; node = getPreviousNode()) {
+ if (acceptNode(node))
+ return node;
+ }
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java
new file mode 100644
index 0000000000..4bfed52901
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Vector;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * NodeListImpl class
+ */
+public class NodeListImpl implements NodeList {
+
+ Object lockObject = new byte[0];
+
+ private Vector nodes = null;
+
+ /**
+ * NodeListImpl constructor
+ */
+ public NodeListImpl() {
+ super();
+ }
+
+ /**
+ * appendNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param node
+ * org.w3c.dom.Node
+ */
+ protected Node appendNode(Node node) {
+ if (node == null)
+ return null;
+ if (this.nodes == null)
+ this.nodes = new Vector();
+ this.nodes.addElement(node);
+ return node;
+ }
+
+ /**
+ * getLength method
+ *
+ * @return int
+ */
+ public int getLength() {
+ synchronized (lockObject) {
+ if (this.nodes == null)
+ return 0;
+ return this.nodes.size();
+ }
+ }
+
+ /**
+ */
+ protected Node insertNode(Node node, int index) {
+ if (node == null)
+ return null;
+ if (this.nodes == null || index >= this.nodes.size()) {
+ return appendNode(node);
+ }
+ this.nodes.insertElementAt(node, index);
+ return node;
+ }
+
+ /**
+ * item method
+ *
+ * @return org.w3c.dom.Node
+ */
+ public Node item(int index) {
+ synchronized (lockObject) {
+ if (this.nodes == null)
+ return null;
+ if (index < 0 || index >= this.nodes.size())
+ return null;
+ return (Node) this.nodes.elementAt(index);
+ }
+ }
+
+ /**
+ * removeNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param index
+ * int
+ */
+ protected Node removeNode(int index) {
+ if (this.nodes == null)
+ return null; // no node
+ if (index < 0 || index >= this.nodes.size())
+ return null; // invalid parameter
+
+ Node removed = (Node) this.nodes.elementAt(index);
+ this.nodes.removeElementAt(index);
+ return removed;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java
new file mode 100644
index 0000000000..e0489499ed
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.Notation;
+
+/**
+ * NotationImpl class
+ */
+public class NotationImpl extends NodeImpl implements Notation {
+
+ private String name = null;
+ private String publicId = null;
+ private String systemId = null;
+
+ /**
+ * NotationImpl constructor
+ */
+ protected NotationImpl() {
+ super();
+ }
+
+ /**
+ * NotationImpl constructor
+ *
+ * @param that
+ * NotationImpl
+ */
+ protected NotationImpl(NotationImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.name = that.name;
+ this.publicId = that.publicId;
+ this.systemId = that.systemId;
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ NotationImpl cloned = new NotationImpl(this);
+ return cloned;
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ if (this.name == null)
+ return new String();
+ return this.name;
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return NOTATION_NODE;
+ }
+
+ /**
+ * getPublicId method
+ *
+ * @return java.lang.String
+ */
+ public String getPublicId() {
+ return this.publicId;
+ }
+
+ /**
+ * getSystemId method
+ *
+ * @return java.lang.String
+ */
+ public String getSystemId() {
+ return this.systemId;
+ }
+
+ /**
+ * setName method
+ *
+ * @param name
+ * java.lang.String
+ */
+ protected void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * setPublicId method
+ *
+ * @param publicId
+ * java.lang.String
+ */
+ public void setPublicId(String publicId) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ this.publicId = publicId;
+ }
+
+ /**
+ * setSystemId method
+ *
+ * @param systemId
+ * java.lang.String
+ */
+ public void setSystemId(String systemId) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ this.systemId = systemId;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java
new file mode 100644
index 0000000000..de9a4fe014
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java
@@ -0,0 +1,227 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Iterator;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+
+
+/**
+ * ProcessingInstructionImpl class
+ */
+public class ProcessingInstructionImpl extends NodeImpl implements XMLJSPRegionContexts, ProcessingInstruction {
+ private String data = null;
+
+ private String target = null;
+
+ /**
+ * ProcessingInstructionImpl constructor
+ */
+ protected ProcessingInstructionImpl() {
+ super();
+ }
+
+ /**
+ * ProcessingInstructionImpl constructor
+ *
+ * @param that
+ * ProcessingInstructionImpl
+ */
+ protected ProcessingInstructionImpl(ProcessingInstructionImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.target = that.target;
+ this.data = that.getData();
+ }
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ ProcessingInstructionImpl cloned = new ProcessingInstructionImpl(this);
+ return cloned;
+ }
+
+ /**
+ * getData method
+ *
+ * @return java.lang.String
+ */
+ public String getData() {
+ if (this.data != null)
+ return this.data;
+
+ IStructuredDocumentRegion flatNode = getFirstStructuredDocumentRegion();
+ if (flatNode == null)
+ return new String();
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return new String();
+
+ ITextRegion targetRegion = null;
+ ITextRegion dataRegion = null;
+ ITextRegion closeRegion = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_PI_OPEN)
+ continue;
+ if (regionType == XMLRegionContext.XML_PI_CLOSE) {
+ closeRegion = region;
+ } else {
+ if (targetRegion == null)
+ targetRegion = region;
+ else if (dataRegion == null)
+ dataRegion = region;
+ }
+ }
+ if (dataRegion == null)
+ return new String();
+ int offset = dataRegion.getStart();
+ int end = flatNode.getLength();
+ if (closeRegion != null)
+ end = closeRegion.getStart();
+ String source = flatNode.getText();
+ return source.substring(offset, end);
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return getTarget();
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return PROCESSING_INSTRUCTION_NODE;
+ }
+
+ /**
+ * getNodeValue method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeValue() {
+ return getData();
+ }
+
+ /**
+ * getTarget method
+ *
+ * @return java.lang.String
+ */
+ public String getTarget() {
+ if (this.target == null)
+ return new String();
+ return this.target;
+ }
+
+ /**
+ */
+ public boolean isClosed() {
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return true; // will be generated
+ String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode);
+ return (regionType == XMLRegionContext.XML_PI_CLOSE);
+ }
+
+ /**
+ */
+ void resetStructuredDocumentRegions() {
+ this.data = getData();
+ setStructuredDocumentRegion(null);
+ }
+
+ /**
+ * setData method
+ *
+ * @param data
+ * java.lang.String
+ */
+ public void setData(String data) throws DOMException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.data = data;
+
+ notifyValueChanged();
+ }
+
+ /**
+ * setNodeValue method
+ *
+ * @param nodeValue
+ * java.lang.String
+ */
+ public void setNodeValue(String nodeValue) throws DOMException {
+ setData(nodeValue);
+ }
+
+ /**
+ */
+ void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ super.setStructuredDocumentRegion(flatNode);
+ if (flatNode != null)
+ this.data = null;
+ }
+
+ /**
+ * setTarget method
+ *
+ * @param target
+ * java.lang.String
+ */
+ protected void setTarget(String target) {
+ this.target = target;
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(getTarget());
+ buffer.append('(');
+ buffer.append(getData());
+ buffer.append(')');
+ return buffer.toString();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java
new file mode 100644
index 0000000000..1c54ba53d0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java
@@ -0,0 +1,630 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.w3c.dom.ranges.Range;
+import org.w3c.dom.ranges.RangeException;
+
+
+/**
+ */
+public class RangeImpl implements Range {
+ private Node endContainer = null;
+ private int endOffset = 0;
+
+ private Node startContainer = null;
+ private int startOffset = 0;
+
+ /**
+ */
+ protected RangeImpl() {
+ super();
+ }
+
+ /**
+ */
+ protected RangeImpl(RangeImpl that) {
+ super();
+
+ if (that != null) {
+ this.startContainer = that.startContainer;
+ this.startOffset = that.startOffset;
+ this.endContainer = that.endContainer;
+ this.endOffset = that.endOffset;
+ }
+ }
+
+ /**
+ * Duplicates the contents of a Range
+ *
+ * @return A DocumentFragment that contains content equivalent to this
+ * Range.
+ * @exception DOMException
+ * HIERARCHY_REQUEST_ERR: Raised if a DocumentType node
+ * would be extracted into the new DocumentFragment. <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public DocumentFragment cloneContents() throws DOMException {
+ // not supported
+ return null;
+ }
+
+ /**
+ * Produces a new Range whose boundary-points are equal to the
+ * boundary-points of the Range.
+ *
+ * @return The duplicated Range.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public Range cloneRange() throws DOMException {
+ return new RangeImpl(this);
+ }
+
+ /**
+ * Collapse a Range onto one of its boundary-points
+ *
+ * @param toStartIf
+ * TRUE, collapses the Range onto its start; if FALSE,
+ * collapses it onto its end.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void collapse(boolean toStart) throws DOMException {
+ if (toStart) {
+ this.endContainer = this.startContainer;
+ this.endOffset = this.startOffset;
+ } else {
+ this.startContainer = this.endContainer;
+ this.startOffset = this.endOffset;
+ }
+ }
+
+ /**
+ * Compare the boundary-points of two Ranges in a document.
+ *
+ * @param howA
+ * code representing the type of comparison, as defined above.
+ * @param sourceRangeThe
+ * <code>Range</code> on which this current
+ * <code>Range</code> is compared to.
+ * @return -1, 0 or 1 depending on whether the corresponding
+ * boundary-point of the Range is respectively before, equal to,
+ * or after the corresponding boundary-point of
+ * <code>sourceRange</code>.
+ * @exception DOMException
+ * WRONG_DOCUMENT_ERR: Raised if the two Ranges are not in
+ * the same Document or DocumentFragment. <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public short compareBoundaryPoints(short how, Range sourceRange) throws DOMException {
+ if (sourceRange == null)
+ return (short) 0; // error
+
+ Node container1 = null;
+ int offset1 = 0;
+ Node container2 = null;
+ int offset2 = 0;
+
+ switch (how) {
+ case START_TO_START :
+ container1 = this.startContainer;
+ offset1 = this.startOffset;
+ container2 = sourceRange.getStartContainer();
+ offset2 = sourceRange.getStartOffset();
+ break;
+ case START_TO_END :
+ container1 = this.startContainer;
+ offset1 = this.startOffset;
+ container2 = sourceRange.getEndContainer();
+ offset2 = sourceRange.getEndOffset();
+ break;
+ case END_TO_END :
+ container1 = this.endContainer;
+ offset1 = this.endOffset;
+ container2 = sourceRange.getEndContainer();
+ offset2 = sourceRange.getEndOffset();
+ break;
+ case END_TO_START :
+ container1 = this.endContainer;
+ offset1 = this.endOffset;
+ container2 = sourceRange.getStartContainer();
+ offset2 = sourceRange.getStartOffset();
+ break;
+ default :
+ return (short) 0; // error
+ }
+
+ return comparePoints(container1, offset1, container2, offset2);
+ }
+
+ /*
+ */
+ protected short comparePoints(Node container1, int offset1, Node container2, int offset2) {
+ if (container1 == null || container2 == null)
+ return (short) 0; // error
+
+ if (container1 == container2) {
+ if (offset1 > offset2)
+ return (short) 1;
+ if (offset1 < offset2)
+ return (short) -1;
+ return 0;
+ }
+
+ // get node offsets
+ XMLNode node1 = null;
+ if (container1.hasChildNodes()) {
+ Node child = container1.getFirstChild();
+ for (int i = 0; i < offset1; i++) {
+ Node next = child.getNextSibling();
+ if (next == null)
+ break;
+ child = next;
+ }
+ node1 = (XMLNode) child;
+ offset1 = 0;
+ } else {
+ node1 = (XMLNode) container1;
+ }
+ int nodeOffset1 = node1.getStartOffset();
+ XMLNode node2 = null;
+ if (container2.hasChildNodes()) {
+ Node child = container2.getFirstChild();
+ for (int i = 0; i < offset2; i++) {
+ Node next = child.getNextSibling();
+ if (next == null)
+ break;
+ child = next;
+ }
+ node2 = (XMLNode) child;
+ offset2 = 0;
+ } else {
+ node2 = (XMLNode) container1;
+ }
+ int nodeOffset2 = node2.getStartOffset();
+
+ if (nodeOffset1 > nodeOffset2)
+ return (short) 1;
+ if (nodeOffset1 < nodeOffset2)
+ return (short) -1;
+ if (offset1 > offset2)
+ return (short) 1;
+ if (offset1 < offset2)
+ return (short) -1;
+ return (short) 0;
+ }
+
+ /**
+ * Removes the contents of a Range from the containing document or
+ * document fragment without returning a reference to the removed content.
+ *
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of
+ * the content of the Range is read-only or any of the
+ * nodes that contain any of the content of the Range are
+ * read-only. <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void deleteContents() throws DOMException {
+ // not supported
+ }
+
+ /**
+ * Called to indicate that the Range is no longer in use and that the
+ * implementation may relinquish any resources associated with this Range.
+ * Subsequent calls to any methods or attribute getters on this Range will
+ * result in a <code>DOMException</code> being thrown with an error code
+ * of <code>INVALID_STATE_ERR</code>.
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void detach() throws DOMException {
+ this.startContainer = null;
+ this.startOffset = 0;
+ this.endContainer = null;
+ this.endOffset = 0;
+ }
+
+ /**
+ * Moves the contents of a Range from the containing document or document
+ * fragment to a new DocumentFragment.
+ *
+ * @return A DocumentFragment containing the extracted contents.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of
+ * the content of the Range is read-only or any of the
+ * nodes which contain any of the content of the Range are
+ * read-only. <br>
+ * HIERARCHY_REQUEST_ERR: Raised if a DocumentType node
+ * would be extracted into the new DocumentFragment. <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public DocumentFragment extractContents() throws DOMException {
+ // not supported
+ return null;
+ }
+
+ /**
+ * TRUE if the Range is collapsed
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public boolean getCollapsed() throws DOMException {
+ if (this.startContainer == this.endContainer && this.startOffset == this.endOffset)
+ return true;
+ return false;
+ }
+
+ /**
+ * The deepest common ancestor container of the Range's two
+ * boundary-points.
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public Node getCommonAncestorContainer() throws DOMException {
+ if (this.startContainer == null)
+ return null;
+ return ((NodeImpl) this.startContainer).getCommonAncestor(this.endContainer);
+ }
+
+ /**
+ * Node within which the Range ends
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public Node getEndContainer() throws DOMException {
+ return this.endContainer;
+ }
+
+ /**
+ * Offset within the ending node of the Range.
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public int getEndOffset() throws DOMException {
+ return this.endOffset;
+ }
+
+ /**
+ * Node within which the Range begins
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public Node getStartContainer() throws DOMException {
+ return this.startContainer;
+ }
+
+ /**
+ * Offset within the starting node of the Range.
+ *
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public int getStartOffset() throws DOMException {
+ return this.startOffset;
+ }
+
+ /**
+ * Inserts a node into the Document or DocumentFragment at the start of
+ * the Range. If the container is a Text node, this will be split at the
+ * start of the Range (as if the Text node's splitText method was
+ * performed at the insertion point) and the insertion will occur between
+ * the two resulting Text nodes. Adjacent Text nodes will not be
+ * automatically merged. If the node to be inserted is a DocumentFragment
+ * node, the children will be inserted rather than the DocumentFragment
+ * node itself.
+ *
+ * @param newNodeThe
+ * node to insert at the start of the Range
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor
+ * container of the start of the Range is read-only. <br>
+ * WRONG_DOCUMENT_ERR: Raised if <code>newNode</code> and
+ * the container of the start of the Range were not created
+ * from the same document. <br>
+ * HIERARCHY_REQUEST_ERR: Raised if the container of the
+ * start of the Range is of a type that does not allow
+ * children of the type of <code>newNode</code> or if
+ * <code>newNode</code> is an ancestor of the container.
+ * <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if <code>newNode</code>
+ * is an Attr, Entity, Notation, or Document node.
+ */
+ public void insertNode(Node newNode) throws RangeException, DOMException {
+ // not supported
+ }
+
+ /**
+ * Select a node and its contents
+ *
+ * @param refNodeThe
+ * node to select.
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if an ancestor of
+ * <code>refNode</code> is an Entity, Notation or
+ * DocumentType node or if <code>refNode</code> is a
+ * Document, DocumentFragment, Attr, Entity, or Notation
+ * node.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void selectNode(Node refNode) throws RangeException, DOMException {
+ if (refNode == null)
+ return;
+ Node parent = refNode.getParentNode();
+ if (parent == null)
+ return;
+ int index = ((NodeImpl) refNode).getIndex();
+ if (index < 0)
+ return;
+ setStart(parent, index);
+ setEnd(parent, index + 1);
+ }
+
+ /**
+ * Select the contents within a node
+ *
+ * @param refNodeNode
+ * to select from
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code>
+ * or an ancestor of <code>refNode</code> is an Entity,
+ * Notation or DocumentType node.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void selectNodeContents(Node refNode) throws RangeException, DOMException {
+ if (refNode == null)
+ return;
+ if (refNode.getNodeType() == Node.TEXT_NODE) {
+ Text text = (Text) refNode;
+ setStart(refNode, 0);
+ setEnd(refNode, text.getLength());
+ } else {
+ NodeList childNodes = refNode.getChildNodes();
+ int length = (childNodes != null ? childNodes.getLength() : 0);
+ setStart(refNode, 0);
+ setEnd(refNode, length);
+ }
+ }
+
+ /**
+ * Sets the attributes describing the end of a Range.
+ *
+ * @param refNodeThe
+ * <code>refNode</code> value. This parameter must be
+ * different from <code>null</code>.
+ * @param offsetThe
+ * <code>endOffset</code> value.
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code>
+ * or an ancestor of <code>refNode</code> is an Entity,
+ * Notation, or DocumentType node.
+ * @exception DOMException
+ * INDEX_SIZE_ERR: Raised if <code>offset</code> is
+ * negative or greater than the number of child units in
+ * <code>refNode</code>. Child units are 16-bit units if
+ * <code>refNode</code> is a type of CharacterData node
+ * (e.g., a Text or Comment node) or a
+ * ProcessingInstruction node. Child units are Nodes in all
+ * other cases. <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void setEnd(Node refNode, int offset) throws RangeException, DOMException {
+ this.endContainer = refNode;
+ this.endOffset = offset;
+ }
+
+ /**
+ * Sets the end of a Range to be after a node
+ *
+ * @param refNodeRange
+ * ends after <code>refNode</code>.
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if the root container of
+ * <code>refNode</code> is not an Attr, Document or
+ * DocumentFragment node or if <code>refNode</code> is a
+ * Document, DocumentFragment, Attr, Entity, or Notation
+ * node.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void setEndAfter(Node refNode) throws RangeException, DOMException {
+ if (refNode == null)
+ return;
+ Node parent = refNode.getParentNode();
+ if (parent == null)
+ return;
+ int index = ((NodeImpl) refNode).getIndex();
+ if (index < 0)
+ return;
+ setEnd(parent, index + 1);
+ }
+
+ /**
+ * Sets the end position to be before a node.
+ *
+ * @param refNodeRange
+ * ends before <code>refNode</code>
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if the root container of
+ * <code>refNode</code> is not an Attr, Document, or
+ * DocumentFragment node or if <code>refNode</code> is a
+ * Document, DocumentFragment, Attr, Entity, or Notation
+ * node.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void setEndBefore(Node refNode) throws RangeException, DOMException {
+ if (refNode == null)
+ return;
+ Node parent = refNode.getParentNode();
+ if (parent == null)
+ return;
+ int index = ((NodeImpl) refNode).getIndex();
+ if (index < 0)
+ return;
+ setEnd(parent, index);
+ }
+
+ /**
+ * Sets the attributes describing the start of the Range.
+ *
+ * @param refNodeThe
+ * <code>refNode</code> value. This parameter must be
+ * different from <code>null</code>.
+ * @param offsetThe
+ * <code>startOffset</code> value.
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code>
+ * or an ancestor of <code>refNode</code> is an Entity,
+ * Notation, or DocumentType node.
+ * @exception DOMException
+ * INDEX_SIZE_ERR: Raised if <code>offset</code> is
+ * negative or greater than the number of child units in
+ * <code>refNode</code>. Child units are 16-bit units if
+ * <code>refNode</code> is a type of CharacterData node
+ * (e.g., a Text or Comment node) or a
+ * ProcessingInstruction node. Child units are Nodes in all
+ * other cases. <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void setStart(Node refNode, int offset) throws RangeException, DOMException {
+ this.startContainer = refNode;
+ this.startOffset = offset;
+ }
+
+ /**
+ * Sets the start position to be after a node
+ *
+ * @param refNodeRange
+ * starts after <code>refNode</code>
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if the root container of
+ * <code>refNode</code> is not an Attr, Document, or
+ * DocumentFragment node or if <code>refNode</code> is a
+ * Document, DocumentFragment, Attr, Entity, or Notation
+ * node.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void setStartAfter(Node refNode) throws RangeException, DOMException {
+ if (refNode == null)
+ return;
+ Node parent = refNode.getParentNode();
+ if (parent == null)
+ return;
+ int index = ((NodeImpl) refNode).getIndex();
+ if (index < 0)
+ return;
+ setStart(parent, index + 1);
+ }
+
+ /**
+ * Sets the start position to be before a node
+ *
+ * @param refNodeRange
+ * starts before <code>refNode</code>
+ * @exception RangeException
+ * INVALID_NODE_TYPE_ERR: Raised if the root container of
+ * <code>refNode</code> is not an Attr, Document, or
+ * DocumentFragment node or if <code>refNode</code> is a
+ * Document, DocumentFragment, Attr, Entity, or Notation
+ * node.
+ * @exception DOMException
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ */
+ public void setStartBefore(Node refNode) throws RangeException, DOMException {
+ if (refNode == null)
+ return;
+ Node parent = refNode.getParentNode();
+ if (parent == null)
+ return;
+ int index = ((NodeImpl) refNode).getIndex();
+ if (index < 0)
+ return;
+ setStart(parent, index);
+ }
+
+ /**
+ * Reparents the contents of the Range to the given node and inserts the
+ * node at the position of the start of the Range.
+ *
+ * @param newParentThe
+ * node to surround the contents with.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor
+ * container of either boundary-point of the Range is
+ * read-only. <br>
+ * WRONG_DOCUMENT_ERR: Raised if <code> newParent</code>
+ * and the container of the start of the Range were not
+ * created from the same document. <br>
+ * HIERARCHY_REQUEST_ERR: Raised if the container of the
+ * start of the Range is of a type that does not allow
+ * children of the type of <code>newParent</code> or if
+ * <code>newParent</code> is an ancestor of the container
+ * or if <code>node</code> would end up with a child node
+ * of a type not allowed by the type of <code>node</code>.
+ * <br>
+ * INVALID_STATE_ERR: Raised if <code>detach()</code> has
+ * already been invoked on this object.
+ * @exception RangeException
+ * BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially
+ * selects a non-text node. <br>
+ * INVALID_NODE_TYPE_ERR: Raised if <code> node</code> is
+ * an Attr, Entity, DocumentType, Notation, Document, or
+ * DocumentFragment node.
+ */
+ public void surroundContents(Node newParent) throws RangeException, DOMException {
+ // not supported
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java
new file mode 100644
index 0000000000..67aa59c493
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java
@@ -0,0 +1,334 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.document.XMLText;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Node;
+
+
+class ReadOnlyController {
+
+ class Span {
+ int length;
+ int offset;
+
+ Span(int offset, int length) {
+ this.offset = offset;
+ this.length = length;
+ }
+ }
+
+ private static ReadOnlyController fInstance;
+
+ static synchronized ReadOnlyController getInstance() {
+ if (fInstance == null) {
+ fInstance = new ReadOnlyController();
+ }
+ return fInstance;
+ }
+
+ static private void lock(IStructuredDocument doc, int offset, int length, boolean canInsertBefore, boolean canInsertAfter) {
+ if (doc == null) {
+ return;
+ }
+ doc.makeReadOnly(offset, length);
+ }
+
+ static private void lock(IStructuredDocumentRegion node, boolean canInsertBefore, boolean canInsertAfter) {
+ if (node == null) {
+ return;
+ }
+ IStructuredDocument doc = node.getParentDocument();
+ if (doc == null) {
+ return;
+ }
+ doc.makeReadOnly(node.getStart(), node.getLength());
+ }
+
+ static private void unlock(IStructuredDocumentRegion node) {
+ if (node == null) {
+ return;
+ }
+ IStructuredDocument doc = node.getParentDocument();
+ if (doc == null) {
+ return;
+ }
+ doc.clearReadOnly(node.getStart(), node.getLength());
+ }
+
+ private ReadOnlyController() {
+ super();
+ }
+
+ private Span getDataSpan(XMLNode node) {
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE :
+ return getDataSpanForElement((XMLElement) node);
+ case Node.TEXT_NODE :
+ return getDataSpanForText((XMLText) node);
+ default :
+ return new Span(0, -1);
+ }
+ }
+
+ private Span getDataSpanForElement(XMLElement node) {
+ IStructuredDocumentRegion docRegion = node.getStartStructuredDocumentRegion();
+ if (docRegion == null) {
+ return new Span(0, -1);
+ }
+
+ ITextRegionList regions = docRegion.getRegions();
+ if (regions == null) {
+ return new Span(0, -1);
+ }
+
+ String startType;
+ String endType;
+ if (node.isCommentTag()) {
+ startType = XMLRegionContext.XML_COMMENT_OPEN;
+ endType = XMLRegionContext.XML_COMMENT_CLOSE;
+ } else {
+ startType = XMLRegionContext.XML_TAG_NAME;
+ endType = XMLRegionContext.XML_TAG_CLOSE;
+ }
+
+ int startOffset = -1;
+ int endOffset = -1;
+ ITextRegion prevRegion = null;
+ ITextRegion region;
+ for (int i = 0; i < regions.size(); i++) {
+ region = regions.get(i);
+ String type = region.getType();
+ if (type == startType) {
+ startOffset = region.getEnd();
+ } else if (type == endType && prevRegion != null) {
+ endOffset = prevRegion.getTextEnd();
+ }
+ prevRegion = region;
+ }
+
+ if (0 <= startOffset && 0 <= endOffset) {
+ return new Span(startOffset, endOffset - startOffset);
+ } else {
+ return new Span(0, -1);
+ }
+ }
+
+ private Span getDataSpanForText(XMLText node) {
+ IStructuredDocumentRegion docRegion = ((NodeImpl) node).getStructuredDocumentRegion();
+ if (docRegion == null) {
+ return new Span(0, -1);
+ }
+ return new Span(0, docRegion.getLength());
+ }
+
+ /**
+ * This method is used from parent's setChildEditable()
+ *
+ * case 1:<parent><node attr="value"/> <node2></parent>
+ * x####################x case 2:<parent><node attr="value"> <child>
+ * </child> </node> </parent> x###################? ?#######x (? :
+ * editable if node.isEditable() == true)
+ */
+ void lockBoth(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ IStructuredDocumentRegion flatNode;
+ boolean canInsert = false;
+
+ // end node (element)
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ flatNode = node.getEndStructuredDocumentRegion();
+ if (flatNode != null) {
+ canInsert = node.isChildEditable();
+ lock(flatNode, canInsert, false);
+ }
+ }
+ // start node
+ flatNode = node.getStartStructuredDocumentRegion();
+ if (flatNode != null) {
+ lock(flatNode, false, canInsert);
+ }
+ }
+
+ void lockData(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ Span span = getDataSpan(node);
+ if (0 <= span.length) {
+ lock(node.getModel().getStructuredDocument(), node.getStartOffset() + span.offset, span.length, false, false);
+ }
+ }
+
+ /**
+ * lock itself and all descendants
+ */
+ void lockDeep(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ int offset = node.getStartOffset();
+ int length = node.getEndOffset() - offset;
+
+ boolean canInsert = true;
+ XMLNode parent = (XMLNode) node.getParentNode();
+ if (parent != null && !parent.isChildEditable()) {
+ canInsert = false;
+ }
+ lock(node.getStructuredDocument(), offset, length, canInsert, canInsert);
+ }
+
+ /**
+ * This method is used from parent's setChildEditable()
+ *
+ * case 1:<parent><node attr="value"/> <node2></parent> x######x x##x
+ * case 2:<parent><node attr="value"> <child></child> </node> </parent>
+ * x######x x#? ?#######x (? : editable if node.isEditable() == true)
+ */
+ void lockNode(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+ if (!node.isDataEditable()) {
+ lockBoth(node);
+ return;
+ }
+
+ IStructuredDocumentRegion flatNode;
+ boolean canInsert = false;
+
+ // end node (element)
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ flatNode = node.getEndStructuredDocumentRegion();
+ if (flatNode != null) {
+ canInsert = node.isChildEditable();
+ lock(flatNode, canInsert, false);
+ }
+ }
+ // start node
+ flatNode = node.getStartStructuredDocumentRegion();
+ if (flatNode != null) {
+ Span span = getDataSpan(node);
+ if (0 <= span.length) {
+ IStructuredDocument structuredDocument = flatNode.getParentDocument();
+ int offset, length;
+ offset = flatNode.getStart();
+ length = span.offset;
+ lock(structuredDocument, offset, length, false, false);
+ offset = offset + span.offset + span.length;
+ length = flatNode.getEnd() - offset;
+ lock(structuredDocument, offset, length, canInsert, false);
+ } else {
+ lock(flatNode, false, canInsert);
+ }
+ }
+ }
+
+ private void unlock(IStructuredDocument doc, int offset, int length) {
+ if (doc == null) {
+ return;
+ }
+ doc.clearReadOnly(offset, length);
+ }
+
+ void unlockBoth(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ IStructuredDocumentRegion flatNode;
+ // start node
+ flatNode = node.getStartStructuredDocumentRegion();
+ if (flatNode != null) {
+ unlock(flatNode);
+ }
+ // end node
+ flatNode = node.getEndStructuredDocumentRegion();
+ if (flatNode != null) {
+ unlock(flatNode);
+ }
+ }
+
+ void unlockData(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ Span span = getDataSpan(node);
+ if (0 <= span.length) {
+ unlock(node.getModel().getStructuredDocument(), span.offset, span.length);
+ }
+ }
+
+ void unlockDeep(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ int offset = node.getStartOffset();
+ int length = node.getEndOffset() - offset;
+
+ unlock(node.getStructuredDocument(), offset, length);
+ }
+
+ void unlockNode(XMLNode node) {
+ if (node == null) {
+ return;
+ }
+
+ IStructuredDocumentRegion flatNode;
+ // end node
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ flatNode = node.getEndStructuredDocumentRegion();
+ if (flatNode != null) {
+ unlock(flatNode);
+ }
+ }
+
+ // start node
+ flatNode = node.getStartStructuredDocumentRegion();
+ if (flatNode != null) {
+ if (node.isDataEditable()) {
+ unlock(flatNode);
+ } else {
+ Span span = getDataSpan(node);
+ if (span.length <= 0) {
+ unlock(flatNode);
+ } else {
+ IStructuredDocument structuredDocument = flatNode.getParentDocument();
+ int offset, length;
+ offset = flatNode.getStart();
+ length = span.offset - offset;
+ unlock(structuredDocument, offset, length);
+ offset = span.offset + span.length;
+ length = flatNode.getEnd() - span.offset;
+ unlock(structuredDocument, offset, length);
+ }
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java
new file mode 100644
index 0000000000..3b3d941c6c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.internal.nls.ResourceHandler1;
+import org.eclipse.wst.xml.core.document.InvalidCharacterException;
+import org.eclipse.wst.xml.core.document.JSPTag;
+import org.eclipse.wst.xml.core.document.XMLCharEntity;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Node;
+
+
+/**
+ */
+public class SourceValidator {
+
+ private NodeImpl node = null;
+
+ /**
+ */
+ public SourceValidator(Node node) {
+ super();
+
+ if (node != null) {
+ this.node = (NodeImpl) node;
+ }
+ }
+
+ /**
+ */
+ public String convertSource(String source) {
+ if (source == null)
+ return null;
+ if (this.node == null)
+ return null; // error
+
+ // setup conversion conditions
+ boolean acceptTag = false;
+ boolean acceptClose = false;
+ boolean acceptQuote = false;
+ boolean acceptAmpersand = false;
+ boolean acceptEntityRef = true;
+ boolean acceptJSPEnd = true;
+ String endTagName = null;
+ if (this.node.getNodeType() == Node.ATTRIBUTE_NODE) {
+ XMLDocument document = (XMLDocument) this.node.getOwnerDocument();
+ if (document != null && document.isJSPType())
+ acceptTag = true;
+ if (acceptTag) {
+ Attr attr = (Attr) this.node;
+ ElementImpl element = (ElementImpl) attr.getOwnerElement();
+ if (element != null && element.isJSPTag())
+ acceptTag = false;
+ }
+ // if the source does not include single quote,
+ // double quote is valid
+ acceptQuote = (source.indexOf('\'') < 0);
+ } else if (this.node.getNodeType() == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) this.node;
+ if (text.isJSPContent()) {
+ int index = source.indexOf(JSPTag.TAG_CLOSE);
+ if (index < 0)
+ return source;
+ acceptTag = true;
+ acceptClose = true;
+ acceptQuote = true;
+ acceptAmpersand = true;
+ acceptJSPEnd = false;
+ } else if (text.isCDATAContent()) {
+ endTagName = text.getParentNode().getNodeName();
+ if (endTagName == null)
+ return null; // error
+ acceptTag = true;
+ acceptClose = true;
+ acceptQuote = true;
+ acceptAmpersand = true;
+ }
+ } else {
+ XMLDocument document = null;
+ if (this.node.getNodeType() == Node.DOCUMENT_NODE) {
+ document = (XMLDocument) this.node;
+ } else {
+ document = (XMLDocument) this.node.getOwnerDocument();
+ }
+ if (document != null && document.isJSPType())
+ acceptTag = true;
+ }
+
+ StringBuffer buffer = null;
+ int copiedLength = 0;
+ int length = source.length();
+ for (int i = 0; i < length; i++) {
+ String ref = null;
+ char c = source.charAt(i);
+ switch (c) {
+ case '<' :
+ if (acceptTag) {
+ if (endTagName != null) {
+ if (!matchEndTag(source, i + 1, endTagName))
+ continue;
+ } else {
+ int skip = skipTag(source, i + 1);
+ if (skip >= 0) {
+ i += skip;
+ continue;
+ }
+ }
+ // invalid JSP tag
+ }
+ ref = XMLCharEntity.LT_REF;
+ break;
+ case '>' :
+ if (acceptClose)
+ continue;
+ ref = XMLCharEntity.GT_REF;
+ break;
+ case '&' :
+ if (acceptAmpersand)
+ continue;
+ if (acceptEntityRef) {
+ int skip = skipEntityRef(source, i + 1);
+ if (skip >= 0) {
+ i += skip;
+ continue;
+ }
+ }
+ ref = XMLCharEntity.AMP_REF;
+ break;
+ case '"' :
+ if (acceptQuote)
+ continue;
+ ref = XMLCharEntity.QUOT_REF;
+ break;
+ case '%' :
+ if (acceptJSPEnd)
+ continue;
+ if (source.charAt(i + 1) != '>')
+ continue;
+ i++;
+ ref = XMLCharEntity.GT_REF;
+ break;
+ default :
+ continue;
+ }
+
+ if (ref != null) {
+ if (buffer == null) {
+ buffer = new StringBuffer(length + 8);
+ }
+ if (i > copiedLength) {
+ buffer.append(source.substring(copiedLength, i));
+ }
+ buffer.append(ref);
+ copiedLength = i + 1; // skip this character
+ }
+ }
+
+ if (buffer != null) {
+ if (copiedLength < length) {
+ buffer.append(source.substring(copiedLength, length));
+ }
+ return buffer.toString();
+ }
+ return source;
+ }
+
+ /**
+ */
+ private final boolean matchEndTag(String source, int offset, String endTagName) {
+ if (source == null || endTagName == null)
+ return false;
+ int length = source.length();
+ if (offset < 0 || offset >= length)
+ return false;
+ if (source.charAt(offset) != '/')
+ return false;
+ offset++;
+ int end = offset + endTagName.length();
+ if (end > length)
+ return false;
+ return endTagName.equalsIgnoreCase(source.substring(offset, end));
+ }
+
+ /**
+ */
+ private final int skipEntityRef(String source, int offset) {
+ if (source == null)
+ return -1;
+ if (offset < 0 || offset >= source.length())
+ return -1;
+ DocumentImpl document = (DocumentImpl) this.node.getOwnerDocument();
+ if (document == null)
+ return -1; // error
+
+ int end = source.indexOf(';', offset);
+ if (end < 0 || end == offset)
+ return -1;
+ String name = source.substring(offset, end);
+ if (name == null || document.getCharValue(name) == null)
+ return -1;
+ return (end + 1 - offset);
+ }
+
+ /**
+ */
+ private final int skipTag(String source, int offset) {
+ if (source == null)
+ return -1;
+ if (offset < 0 || offset >= source.length())
+ return -1;
+
+ int end = offset;
+ if (source.charAt(offset) == '%') {
+ // JSP tag
+ int found = source.indexOf(JSPTag.TAG_CLOSE, offset + 1);
+ if (found < 0)
+ return -1; // invalid JSP tag
+ end = found + 2;
+ } else {
+ // normal tag
+ int found = source.indexOf('>', offset);
+ if (found < 0)
+ return -1; // invalid tag
+ end = found + 1;
+ }
+ return (end - offset);
+ }
+
+ /**
+ */
+ public boolean validateSource(String source) throws InvalidCharacterException {
+ if (source == null)
+ return true;
+ if (this.node == null)
+ return false; // error
+ String message = null;
+
+ // setup validation conditions
+ boolean acceptTag = false;
+ boolean acceptClose = false;
+ boolean acceptQuote = true;
+ boolean acceptEntityRef = true;
+ String endTagName = null;
+ if (this.node.getNodeType() == Node.ATTRIBUTE_NODE) {
+ XMLDocument document = (XMLDocument) this.node.getOwnerDocument();
+ if (document != null && document.isJSPType())
+ acceptTag = true;
+ if (acceptTag) {
+ Attr attr = (Attr) this.node;
+ ElementImpl element = (ElementImpl) attr.getOwnerElement();
+ if (element != null && element.isJSPTag())
+ acceptTag = false;
+ }
+ // if the source does not include single quote,
+ // double quote is valid
+ acceptQuote = (source.indexOf('\'') < 0);
+ } else if (this.node.getNodeType() == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) this.node;
+ if (text.isJSPContent()) {
+ int index = source.indexOf(JSPTag.TAG_CLOSE);
+ if (index < 0)
+ return true;
+ message = ResourceHandler1.getString("Invalid_character_('>')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('>') found"
+ throw new InvalidCharacterException(message, '>', index + 1);
+ } else if (text.isCDATAContent()) {
+ endTagName = text.getParentNode().getNodeName();
+ if (endTagName == null)
+ return false; // error
+ acceptTag = true;
+ acceptClose = true;
+ }
+ } else {
+ XMLDocument document = null;
+ if (this.node.getNodeType() == Node.DOCUMENT_NODE) {
+ document = (XMLDocument) this.node;
+ } else {
+ document = (XMLDocument) this.node.getOwnerDocument();
+ }
+ if (document != null && document.isJSPType())
+ acceptTag = true;
+ }
+
+ char c = 0;
+ int length = source.length();
+ for (int i = 0; i < length; i++) {
+ c = source.charAt(i);
+ switch (c) {
+ case '<' :
+ if (acceptTag) {
+ if (endTagName != null) {
+ if (!matchEndTag(source, i + 1, endTagName))
+ continue;
+ } else {
+ int skip = skipTag(source, i + 1);
+ if (skip >= 0) {
+ i += skip;
+ continue;
+ }
+ }
+ // invalid tag
+ }
+ message = ResourceHandler1.getString("Invalid_character_('<')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('<') found"
+ break;
+ case '>' :
+ if (acceptClose)
+ continue;
+ message = ResourceHandler1.getString("Invalid_character_('>')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('>') found"
+ break;
+ case '&' :
+ if (acceptEntityRef) {
+ if (endTagName != null)
+ continue;
+ int skip = skipEntityRef(source, i + 1);
+ if (skip >= 0) {
+ i += skip;
+ continue;
+ }
+ // invalid entity reference
+ }
+ message = ResourceHandler1.getString("Invalid_character_('&')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('&') found"
+ break;
+ case '"' :
+ if (acceptQuote)
+ continue;
+ message = ResourceHandler1.getString("Invalid_character_('__')_f_EXC_"); //$NON-NLS-1$ = "Invalid character ('\"') found"
+ break;
+ default :
+ continue;
+ }
+
+ if (message != null) {
+ throw new InvalidCharacterException(message, c, i);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java
new file mode 100644
index 0000000000..47a50fd2c8
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.w3c.dom.Node;
+
+
+/**
+ * This class is only for debug purpose.
+ */
+public class StructuredDocumentRegionChecker {
+ String EOL = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ private int offset = 0;
+ Writer testWriter = null;
+
+ /**
+ */
+ public StructuredDocumentRegionChecker() {
+ super();
+ }
+
+ public StructuredDocumentRegionChecker(Writer writer) {
+ super();
+ testWriter = writer;
+ }
+
+ /**
+ */
+ private void checkChildNodes(Node node) {
+ for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+ checkNode(child);
+ }
+ }
+
+ /**
+ */
+ public void checkModel(XMLModel model) {
+ checkChildNodes(model.getDocument());
+ }
+
+ /**
+ */
+ private void checkNode(Node node) {
+ checkStructuredDocumentRegion(((NodeImpl) node).getStructuredDocumentRegion());
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ checkChildNodes(node);
+ checkStructuredDocumentRegion(((ElementImpl) node).getEndStructuredDocumentRegion());
+ }
+ }
+
+ /**
+ */
+ private void checkStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return;
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int n = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < n; i++) {
+ IStructuredDocumentRegion c = container.getStructuredDocumentRegion(i);
+ if (c == null) {
+ reportError("null"); //$NON-NLS-1$
+ continue;
+ }
+ checkStructuredDocumentRegion(c);
+ }
+ return;
+ }
+
+ int start = flatNode.getStart();
+ if (start < this.offset)
+ reportError("overwrap"); //$NON-NLS-1$
+ if (start > this.offset)
+ reportError("gap"); //$NON-NLS-1$
+ int end = flatNode.getEnd();
+ this.offset = end;
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ IStructuredDocumentRegion p = proxy.getStructuredDocumentRegion();
+ if (p == null) {
+ reportError("null"); //$NON-NLS-1$
+ return;
+ }
+ int s = p.getStart();
+ int e = p.getEnd();
+ if (s > start || e < end)
+ reportError("out"); //$NON-NLS-1$
+ if (s == start && e == end)
+ reportWarning("vain"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ */
+ private void reportError(String message) {
+ String msg = "StructuredDocumentRegionChecker : error : " + message; //$NON-NLS-1$
+ if (testWriter != null) {
+ try {
+ testWriter.write(msg + EOL);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println(msg);
+ }
+ throw new StructuredDocumentRegionManagementException();
+ }
+
+ /**
+ */
+ private void reportWarning(String message) {
+ String msg = "StructuredDocumentRegionChecker : warning : " + message; //$NON-NLS-1$
+ if (testWriter != null) {
+ try {
+ testWriter.write(msg + EOL);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println(msg);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java
new file mode 100644
index 0000000000..166d8c67b1
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java
@@ -0,0 +1,605 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Vector;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+
+
+class StructuredDocumentRegionContainer implements IStructuredDocumentRegion {
+
+ private Vector flatNodes = new Vector(2);
+
+ /**
+ */
+ StructuredDocumentRegionContainer() {
+ super();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#addRegion(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public void addRegion(ITextRegion aRegion) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjust(int)
+ */
+ public void adjust(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustLengthWith(int)
+ */
+ public void adjustLengthWith(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustStart(int)
+ */
+ public void adjustStart(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ */
+ void appendStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return;
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ if (container.getStructuredDocumentRegionCount() > 0) {
+ this.flatNodes.addAll(container.flatNodes);
+ }
+ } else {
+ this.flatNodes.addElement(flatNode);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(int)
+ */
+ public boolean containsOffset(int i) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(com.ibm.sed.structured.text.ITextRegion,
+ * int)
+ */
+ public boolean containsOffset(ITextRegion region, int i) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#equatePositions(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public void equatePositions(ITextRegion region) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getDeepestRegionAtCharacterOffset(int)
+ */
+ public ITextRegion getDeepestRegionAtCharacterOffset(int offset) {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public int getEnd() {
+ IStructuredDocumentRegion last = getLastStructuredDocumentRegion();
+ if (last == null)
+ return 0;
+ return last.getEnd();
+ }
+
+ /**
+ */
+ public int getEndOffset() {
+ return getEnd();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getEndOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getEndOffset(ITextRegion containedRegion) {
+ // XXX Auto-generated method stub
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getFirstRegion()
+ */
+ public ITextRegion getFirstRegion() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion getFirstStructuredDocumentRegion() {
+ if (this.flatNodes.isEmpty())
+ return null;
+ return (IStructuredDocumentRegion) this.flatNodes.elementAt(0);
+ }
+
+ /**
+ */
+ public String getFullText() {
+ return getText();
+ }
+
+ /**
+ */
+ public String getFullText(ITextRegion aRegion) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public String getFullText(String context) {
+ // not supported
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getLastRegion()
+ */
+ public ITextRegion getLastRegion() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion getLastStructuredDocumentRegion() {
+ int size = this.flatNodes.size();
+ if (size == 0)
+ return null;
+ return (IStructuredDocumentRegion) this.flatNodes.elementAt(size - 1);
+ }
+
+ /**
+ */
+ public int getLength() {
+ return (getEnd() - getStart());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getNext()
+ */
+ public IStructuredDocumentRegion getNext() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public int getNumberOfRegions() {
+ // not supported
+ return 0;
+ }
+
+ /**
+ */
+ public ITextRegionContainer getParent() {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getParentDocument()
+ */
+ public IStructuredDocument getParentDocument() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getPrevious()
+ */
+ public IStructuredDocumentRegion getPrevious() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public ITextRegion getRegionAtCharacterOffset(int offset) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public ITextRegionList getRegions() {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public int getStart() {
+ IStructuredDocumentRegion first = getFirstStructuredDocumentRegion();
+ if (first == null)
+ return 0;
+ return first.getStart();
+ }
+
+ /**
+ */
+ public int getStartOffset() {
+ return getStart();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getStartOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getStartOffset(ITextRegion containedRegion) {
+ // XXX Auto-generated method stub
+ return 0;
+ }
+
+ /**
+ */
+ public IStructuredDocument getStructuredDocument() {
+ IStructuredDocumentRegion first = getFirstStructuredDocumentRegion();
+ if (first == null)
+ return null;
+ return first.getParentDocument();
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion getStructuredDocumentRegion(int index) {
+ if (index < 0 || index >= this.flatNodes.size())
+ return null;
+ return (IStructuredDocumentRegion) this.flatNodes.elementAt(index);
+ }
+
+ /**
+ */
+ int getStructuredDocumentRegionCount() {
+ return this.flatNodes.size();
+ }
+
+ /**
+ */
+ public String getText() {
+ int size = this.flatNodes.size();
+ if (size == 0)
+ return new String();
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < size; i++) {
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) this.flatNodes.elementAt(i);
+ if (flatNode == null)
+ continue;
+ buffer.append(flatNode.getText());
+ }
+ return buffer.toString();
+ }
+
+ /**
+ */
+ public String getText(ITextRegion aRegion) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public String getText(String context) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public int getTextEnd() {
+ return getEnd();
+ }
+
+ /**
+ */
+ public int getTextEndOffset() {
+ return getTextEnd();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getTextEndOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getTextEndOffset(ITextRegion containedRegion) {
+ // XXX Auto-generated method stub
+ return 0;
+ }
+
+ /**
+ * The text length is equal to length if there is no white space at the
+ * end of a region. Otherwise it is smaller than length.
+ */
+ public int getTextLength() {
+ return (getTextEnd() - getStart());
+ }
+
+ /**
+ */
+ public String getType() {
+ return "StructuredDocumentRegionContainer";//$NON-NLS-1$
+ }
+
+ /**
+ */
+ void insertStructuredDocumentRegion(IStructuredDocumentRegion flatNode, int index) {
+ if (flatNode == null)
+ return;
+ if (index < 0)
+ return;
+ int size = this.flatNodes.size();
+ if (index > size)
+ return;
+ if (index == size) {
+ appendStructuredDocumentRegion(flatNode);
+ return;
+ }
+ this.flatNodes.insertElementAt(flatNode, index);
+ }
+
+ public boolean isDeleted() {
+ // I'll assume never really needed here
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#isEnded()
+ */
+ public boolean isEnded() {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion removeStructuredDocumentRegion(int index) {
+ if (index < 0 || index >= this.flatNodes.size())
+ return null;
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) this.flatNodes.elementAt(index);
+ this.flatNodes.removeElementAt(index);
+ return flatNode;
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ if (oldStructuredDocumentRegion == null)
+ return null;
+ int size = this.flatNodes.size();
+ for (int i = 0; i < size; i++) {
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) this.flatNodes.elementAt(i);
+ if (flatNode == oldStructuredDocumentRegion) {
+ this.flatNodes.removeElementAt(i);
+ return flatNode;
+ }
+ }
+ return null; // not found
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion replaceStructuredDocumentRegion(IStructuredDocumentRegion flatNode, int index) {
+ if (flatNode == null)
+ return removeStructuredDocumentRegion(index);
+ if (index < 0 || index >= this.flatNodes.size())
+ return null;
+ IStructuredDocumentRegion oldStructuredDocumentRegion = (IStructuredDocumentRegion) this.flatNodes.elementAt(index);
+ this.flatNodes.setElementAt(flatNode, index);
+ return oldStructuredDocumentRegion;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.IStructuredDocumentRegion,
+ * int)
+ */
+ public boolean sameAs(IStructuredDocumentRegion region, int shift) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /**
+ */
+ public boolean sameAs(ITextRegion region, int shift) {
+ // not support
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.ITextRegion,
+ * com.ibm.sed.structured.text.IStructuredDocumentRegion,
+ * com.ibm.sed.structured.text.ITextRegion, int)
+ */
+ public boolean sameAs(ITextRegion oldRegion, IStructuredDocumentRegion documentRegion, ITextRegion newRegion, int shift) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ public void setDeleted(boolean deleted) {
+ // I'll assume never really needed here
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setEnded(boolean)
+ */
+ public void setEnded(boolean hasEnd) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setLength(int)
+ */
+ public void setLength(int newLength) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setNext(com.ibm.sed.structured.text.IStructuredDocumentRegion)
+ */
+ public void setNext(IStructuredDocumentRegion newNext) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setParentDocument(com.ibm.sed.structured.text.IStructuredDocument)
+ */
+ public void setParentDocument(IStructuredDocument document) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setPrevious(com.ibm.sed.structured.text.IStructuredDocumentRegion)
+ */
+ public void setPrevious(IStructuredDocumentRegion newPrevious) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ */
+ public void setRegions(ITextRegionList embeddedRegions) {
+ // not supported
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setStart(int)
+ */
+ public void setStart(int newStart) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('{');
+ int count = getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ if (i != 0)
+ buffer.append(',');
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(i);
+ if (flatNode == null)
+ buffer.append("null");//$NON-NLS-1$
+ else
+ buffer.append(flatNode.toString());
+ }
+ buffer.append('}');
+ return buffer.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#updateModel(java.lang.Object,
+ * com.ibm.sed.structured.text.IStructuredDocumentRegion,
+ * java.lang.String, int, int)
+ */
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion flatnode, String changes, int start, int end) {
+ // XXX Auto-generated method stub
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java
new file mode 100644
index 0000000000..0057dd537f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+
+
+
+/**
+ */
+public class StructuredDocumentRegionManagementException extends SourceEditingRuntimeException {
+
+ /**
+ * StructuredDocumentRegionManagementException constructor
+ */
+ public StructuredDocumentRegionManagementException() {
+ super("IStructuredDocumentRegion management failed.");//$NON-NLS-1$
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java
new file mode 100644
index 0000000000..1503845032
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java
@@ -0,0 +1,548 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+
+
+class StructuredDocumentRegionProxy implements IStructuredDocumentRegion {
+ private IStructuredDocumentRegion flatNode = null;
+ private int length = 0;
+
+ private int offset = 0;
+
+ /**
+ */
+ StructuredDocumentRegionProxy() {
+ super();
+ }
+
+ /**
+ */
+ StructuredDocumentRegionProxy(int offset, int length) {
+ super();
+
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ */
+ StructuredDocumentRegionProxy(int offset, int length, IStructuredDocumentRegion flatNode) {
+ super();
+
+ this.offset = offset;
+ this.length = length;
+ this.flatNode = flatNode;
+ if (this.flatNode != null)
+ this.offset -= this.flatNode.getStart();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#addRegion(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public void addRegion(ITextRegion aRegion) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjust(int)
+ */
+ public void adjust(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustLengthWith(int)
+ */
+ public void adjustLengthWith(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustStart(int)
+ */
+ public void adjustStart(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(int)
+ */
+ public boolean containsOffset(int i) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(com.ibm.sed.structured.text.ITextRegion,
+ * int)
+ */
+ public boolean containsOffset(ITextRegion region, int i) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#equatePositions(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public void equatePositions(ITextRegion region) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getDeepestRegionAtCharacterOffset(int)
+ */
+ public ITextRegion getDeepestRegionAtCharacterOffset(int offset) {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public int getEnd() {
+ int flatNodeOffset = 0;
+ if (this.flatNode != null)
+ flatNodeOffset = this.flatNode.getStart();
+ return flatNodeOffset + this.offset + this.length;
+ }
+
+ /**
+ */
+ public int getEndOffset() {
+ return getEnd();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getEndOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getEndOffset(ITextRegion containedRegion) {
+ // XXX Auto-generated method stub
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getFirstRegion()
+ */
+ public ITextRegion getFirstRegion() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public String getFullText() {
+ return getText();
+ }
+
+ /**
+ */
+ public String getFullText(ITextRegion aRegion) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public String getFullText(String context) {
+ // not supported
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getLastRegion()
+ */
+ public ITextRegion getLastRegion() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public int getLength() {
+ return this.length;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getNext()
+ */
+ public IStructuredDocumentRegion getNext() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public int getNumberOfRegions() {
+ // not supported
+ return 0;
+ }
+
+ /**
+ */
+ int getOffset() {
+ int flatNodeOffset = 0;
+ if (this.flatNode != null)
+ flatNodeOffset = this.flatNode.getStart();
+ return flatNodeOffset + this.offset;
+ }
+
+ /**
+ */
+ public ITextRegionContainer getParent() {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getParentDocument()
+ */
+ public IStructuredDocument getParentDocument() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getPrevious()
+ */
+ public IStructuredDocumentRegion getPrevious() {
+ // XXX Auto-generated method stub
+ return null;
+ }
+
+ /**
+ */
+ public ITextRegion getRegionAtCharacterOffset(int offset) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public ITextRegionList getRegions() {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public int getStart() {
+ int flatNodeOffset = 0;
+ if (this.flatNode != null)
+ flatNodeOffset = this.flatNode.getStart();
+ return flatNodeOffset + this.offset;
+ }
+
+ /**
+ */
+ public int getStartOffset() {
+ return getStart();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getStartOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getStartOffset(ITextRegion containedRegion) {
+ // XXX Auto-generated method stub
+ return 0;
+ }
+
+ /**
+ */
+ public IStructuredDocument getStructuredDocument() {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion getStructuredDocumentRegion() {
+ return this.flatNode;
+ }
+
+ /**
+ */
+ public String getText() {
+ if (this.flatNode == null)
+ return new String();
+ String text = this.flatNode.getText();
+ if (text == null)
+ return new String();
+ int end = this.offset + this.length;
+ return text.substring(this.offset, end);
+ }
+
+ /**
+ */
+ public String getText(ITextRegion aRegion) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public String getText(String context) {
+ // not supported
+ return null;
+ }
+
+ /**
+ */
+ public int getTextEnd() {
+ return getEnd();
+ }
+
+ /**
+ */
+ public int getTextEndOffset() {
+ return getTextEnd();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getTextEndOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getTextEndOffset(ITextRegion containedRegion) {
+ // XXX Auto-generated method stub
+ return 0;
+ }
+
+ /**
+ * The text length is equal to length if there is no white space at the
+ * end of a region. Otherwise it is smaller than length.
+ */
+ public int getTextLength() {
+ return getLength();
+ }
+
+ /**
+ */
+ public String getType() {
+ return "StructuredDocumentRegionProxy";//$NON-NLS-1$
+ }
+
+ public boolean isDeleted() {
+ // I'll assume never really needed here
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#isEnded()
+ */
+ public boolean isEnded() {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.IStructuredDocumentRegion,
+ * int)
+ */
+ public boolean sameAs(IStructuredDocumentRegion region, int shift) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ /**
+ */
+ public boolean sameAs(ITextRegion region, int shift) {
+ // not supported
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.ITextRegion,
+ * com.ibm.sed.structured.text.IStructuredDocumentRegion,
+ * com.ibm.sed.structured.text.ITextRegion, int)
+ */
+ public boolean sameAs(ITextRegion oldRegion, IStructuredDocumentRegion documentRegion, ITextRegion newRegion, int shift) {
+ // XXX Auto-generated method stub
+ return false;
+ }
+
+ public void setDeleted(boolean deleted) {
+ // I'll assume never really needed here
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setEnded(boolean)
+ */
+ public void setEnded(boolean hasEnd) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ * had to make public, due to API transition.
+ */
+ public void setLength(int length) {
+ this.length = length;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setNext(com.ibm.sed.structured.text.IStructuredDocumentRegion)
+ */
+ public void setNext(IStructuredDocumentRegion newNext) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ */
+ void setOffset(int offset) {
+ this.offset = offset;
+ if (this.flatNode != null)
+ this.offset -= this.flatNode.getStart();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setParentDocument(com.ibm.sed.structured.text.IStructuredDocument)
+ */
+ public void setParentDocument(IStructuredDocument document) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setPrevious(com.ibm.sed.structured.text.IStructuredDocumentRegion)
+ */
+ public void setPrevious(IStructuredDocumentRegion newPrevious) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ */
+ public void setRegions(ITextRegionList embeddedRegions) {
+ // not supported
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setStart(int)
+ */
+ public void setStart(int newStart) {
+ // XXX Auto-generated method stub
+
+ }
+
+ /**
+ */
+ void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (this.flatNode != null)
+ this.offset += this.flatNode.getStart();
+ this.flatNode = flatNode;
+ if (this.flatNode != null)
+ this.offset -= flatNode.getStart();
+ }
+
+ /**
+ * toString method
+ *
+ * @return java.lang.String
+ */
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append('[');
+ buffer.append(getStart());
+ buffer.append(',');
+ buffer.append(getEnd());
+ buffer.append(']');
+ buffer.append('(');
+ if (this.flatNode != null)
+ buffer.append(this.flatNode.toString());
+ else
+ buffer.append("null");//$NON-NLS-1$
+ buffer.append(')');
+ return buffer.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#updateModel(java.lang.Object,
+ * com.ibm.sed.structured.text.IStructuredDocumentRegion,
+ * java.lang.String, int, int)
+ */
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion flatnode, String changes, int start, int end) {
+ // XXX Auto-generated method stub
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java
new file mode 100644
index 0000000000..82c848d940
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+/**
+ * Provides convenient functions to handle IStructuredDocumentRegion and
+ * ITextRegion.
+ */
+class StructuredDocumentRegionUtil implements XMLJSPRegionContexts {
+
+ /**
+ * Extracts contents enclosed with quotes. Quotes may be double or single.
+ */
+ static String getAttrValue(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ if (region == null)
+ return null;
+ if (flatNode == null)
+ return null;
+ String value = flatNode.getText(region);
+ if (value == null)
+ return null;
+ int length = value.length();
+ if (length == 0)
+ return value;
+ char firstChar = value.charAt(0);
+ if (firstChar == '"' || firstChar == '\'') {
+ if (length == 1)
+ return null;
+ if (value.charAt(length - 1) == firstChar)
+ length--;
+ return value.substring(1, length);
+ }
+ return value;
+ }
+
+ /**
+ * Extracts the name without heading '&' and tailing ';'.
+ */
+ static String getEntityRefName(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ if (region == null)
+ return null;
+ String ref = flatNode.getText(region);
+ int length = ref.length();
+ if (length == 0)
+ return ref;
+ int offset = 0;
+ if (ref.charAt(0) == '&')
+ offset = 1;
+ if (ref.charAt(length - 1) == ';')
+ length--;
+ if (offset >= length)
+ return null;
+ return ref.substring(offset, length);
+ }
+
+ /**
+ * Returns the first region.
+ */
+ static ITextRegion getFirstRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null || regions.size() == 0)
+ return null;
+ return regions.get(0);
+ }
+
+ /**
+ * Returns the type of the first region.
+ */
+ static String getFirstRegionType(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return XMLRegionContext.UNDEFINED;
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null || regions.size() == 0)
+ return XMLRegionContext.UNDEFINED;
+ ITextRegion region = regions.get(0);
+ return region.getType();
+ }
+
+ /**
+ */
+ static IStructuredDocumentRegion getFirstStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ flatNode = ((StructuredDocumentRegionContainer) flatNode).getFirstStructuredDocumentRegion();
+ }
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ flatNode = ((StructuredDocumentRegionProxy) flatNode).getStructuredDocumentRegion();
+ }
+ return flatNode;
+ }
+
+ /**
+ * Returns the last region.
+ */
+ static ITextRegion getLastRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null || regions.size() == 0)
+ return null;
+ return regions.get(regions.size() - 1);
+ }
+
+ /**
+ * Returns the type of the first region.
+ */
+ static String getLastRegionType(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return XMLRegionContext.UNDEFINED;
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null || regions.size() == 0)
+ return XMLRegionContext.UNDEFINED;
+ ITextRegion region = regions.get(regions.size() - 1);
+ return region.getType();
+ }
+
+ /**
+ */
+ static IStructuredDocumentRegion getLastStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ flatNode = ((StructuredDocumentRegionContainer) flatNode).getLastStructuredDocumentRegion();
+ }
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ flatNode = ((StructuredDocumentRegionProxy) flatNode).getStructuredDocumentRegion();
+ }
+ return flatNode;
+ }
+
+ /**
+ */
+ static IStructuredDocumentRegion getStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return null;
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ flatNode = ((StructuredDocumentRegionProxy) flatNode).getStructuredDocumentRegion();
+ }
+ return flatNode;
+ }
+
+ StructuredDocumentRegionUtil() {
+ super();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java
new file mode 100644
index 0000000000..826fe54b3b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java
@@ -0,0 +1,1107 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.document.InvalidCharacterException;
+import org.eclipse.wst.xml.core.document.XMLGenerator;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.document.XMLText;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+
+/**
+ * TextImpl class
+ */
+public class TextImpl extends CharacterDataImpl implements XMLText {
+
+ /**
+ */
+ private class StringPair {
+ private String fFirst = null;
+ private String fSecond = null;
+
+ StringPair(String first, String second) {
+ this.fFirst = first;
+ this.fSecond = second;
+ }
+
+ String getFirst() {
+ return this.fFirst;
+ }
+
+ String getSecond() {
+ return this.fSecond;
+ }
+ }
+
+ private String fSource = null;
+
+ /**
+ * TextImpl constructor
+ */
+ protected TextImpl() {
+ super();
+ }
+
+ /**
+ * TextImpl constructor
+ *
+ * @param that
+ * TextImpl
+ */
+ protected TextImpl(TextImpl that) {
+ super(that);
+
+ if (that != null) {
+ this.fSource = that.getSource();
+ }
+ }
+
+ /**
+ * appendData method
+ *
+ * @param arg
+ * java.lang.String
+ */
+ public void appendData(String arg) throws DOMException {
+ if (arg == null || arg.length() == 0)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ String newSource = getSource(arg);
+ if (newSource == null)
+ return;
+ String source = getSource();
+ if (source != null)
+ setTextSource(source + newSource);
+ else
+ setTextSource(newSource);
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion appendStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion) {
+ if (newStructuredDocumentRegion == null)
+ return null;
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null) {
+ setStructuredDocumentRegion(newStructuredDocumentRegion);
+ return newStructuredDocumentRegion;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ container.appendStructuredDocumentRegion(newStructuredDocumentRegion);
+ } else {
+ StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer();
+ container.appendStructuredDocumentRegion(flatNode);
+ container.appendStructuredDocumentRegion(newStructuredDocumentRegion);
+ setStructuredDocumentRegion(container);
+ }
+
+ return newStructuredDocumentRegion;
+ }
+
+ /**
+ * appendText method
+ *
+ * @param text
+ * org.w3c.dom.Text
+ */
+ public void appendText(Text newText) {
+ if (newText == null)
+ return;
+
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ TextImpl text = (TextImpl) newText;
+ String newSource = text.getSource();
+ if (newSource == null && newSource.length() == 0)
+ return;
+ String source = getSource();
+ if (source != null)
+ setTextSource(source + newSource);
+ else
+ setTextSource(newSource);
+ }
+
+ /**
+ * cloneNode method
+ *
+ * @return org.w3c.dom.Node
+ * @param deep
+ * boolean
+ */
+ public Node cloneNode(boolean deep) {
+ TextImpl cloned = new TextImpl(this);
+ return cloned;
+ }
+
+ /**
+ * deleteData method
+ *
+ * @param offset
+ * int
+ * @param count
+ * int
+ */
+ public void deleteData(int offset, int count) throws DOMException {
+ if (count == 0)
+ return;
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ if (count < 0 || offset < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String source = getSource();
+ if (source == null || source.length() == 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ StringPair pair = substringSourceExcluded(source, offset, count);
+ if (pair == null)
+ return;
+ source = null;
+ String first = pair.getFirst();
+ if (first != null)
+ source = first;
+ String second = pair.getSecond();
+ if (second != null) {
+ if (source != null)
+ source += second;
+ else
+ source = second;
+ }
+ if (source == null)
+ source = new String(); // delete all
+ setTextSource(source);
+ }
+
+ /**
+ * getData method
+ *
+ * @return java.lang.String
+ */
+ public String getData() throws DOMException {
+ if (this.fSource != null)
+ return getData(this.fSource);
+ String data = super.getData();
+ if (data != null)
+ return data;
+ return getData(getStructuredDocumentRegion());
+ }
+
+ /**
+ */
+ private String getData(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return new String();
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int length = container.getLength();
+ if (length < 16)
+ length = 16; // default
+ StringBuffer buffer = new StringBuffer(length);
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ String data = getData(content);
+ if (data == null)
+ continue;
+ buffer.append(data);
+ }
+ return buffer.toString();
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ return flatNode.getText();
+ }
+
+ ITextRegion region = StructuredDocumentRegionUtil.getFirstRegion(flatNode);
+ if (region != null) {
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_CHAR_REFERENCE) {
+ String name = StructuredDocumentRegionUtil.getEntityRefName(flatNode, region);
+ if (name != null) {
+ DocumentImpl document = (DocumentImpl) getOwnerDocument();
+ if (document != null) {
+ String value = document.getCharValue(name);
+ if (value != null)
+ return value;
+ }
+ }
+ }
+ }
+
+ return flatNode.getText();
+ }
+
+ /**
+ * Returns data for the source
+ */
+ private String getData(String source) {
+ if (source == null)
+ return null;
+ StringBuffer buffer = null;
+ int offset = 0;
+ int length = source.length();
+ int ref = source.indexOf('&');
+ while (ref >= 0) {
+ int end = source.indexOf(';', ref + 1);
+ if (end > ref + 1) {
+ String name = source.substring(ref + 1, end);
+ String value = getCharValue(name);
+ if (value != null) {
+ if (buffer == null)
+ buffer = new StringBuffer(length);
+ if (ref > offset)
+ buffer.append(source.substring(offset, ref));
+ buffer.append(value);
+ offset = end + 1;
+ ref = end;
+ }
+ }
+ ref = source.indexOf('&', ref + 1);
+ }
+ if (buffer == null)
+ return source;
+ if (length > offset)
+ buffer.append(source.substring(offset));
+ return buffer.toString();
+ }
+
+ /**
+ * getFirstStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getFirstStructuredDocumentRegion() {
+ return StructuredDocumentRegionUtil.getFirstStructuredDocumentRegion(getStructuredDocumentRegion());
+ }
+
+ /**
+ * getLastStructuredDocumentRegion method
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getLastStructuredDocumentRegion() {
+ return StructuredDocumentRegionUtil.getLastStructuredDocumentRegion(getStructuredDocumentRegion());
+ }
+
+ /**
+ * getNodeName method
+ *
+ * @return java.lang.String
+ */
+ public String getNodeName() {
+ return "#text";//$NON-NLS-1$
+ }
+
+ /**
+ * getNodeType method
+ *
+ * @return short
+ */
+ public short getNodeType() {
+ return TEXT_NODE;
+ }
+
+ /**
+ */
+ public String getSource() {
+ if (this.fSource != null)
+ return this.fSource;
+ String data = super.getData();
+ if (data != null && data.length() > 0) {
+ String source = getSource(data);
+ if (source != null)
+ return source;
+ }
+ return super.getSource();
+ }
+
+ /**
+ * Returns source for the data
+ */
+ private String getSource(String data) {
+ if (data == null)
+ return null;
+ XMLModel model = getModel();
+ if (model == null)
+ return null; // error
+ XMLGenerator generator = model.getGenerator();
+ if (generator == null)
+ return null; // error
+ return generator.generateTextData(this, data);
+ }
+
+ /**
+ */
+ String getTextSource() {
+ return this.fSource;
+ }
+
+ /**
+ */
+ public String getValueSource() {
+ return getSource();
+ }
+
+ /**
+ */
+ boolean hasStructuredDocumentRegion(IStructuredDocumentRegion askedStructuredDocumentRegion) {
+ if (askedStructuredDocumentRegion == null)
+ return false;
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return false;
+
+ if (flatNode == askedStructuredDocumentRegion)
+ return true;
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ if (proxy.getStructuredDocumentRegion() == askedStructuredDocumentRegion)
+ return true;
+ return false;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue;
+ if (content == askedStructuredDocumentRegion)
+ return true;
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (proxy.getStructuredDocumentRegion() == askedStructuredDocumentRegion)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ /**
+ * insertData method
+ *
+ * @param offset
+ * int
+ * @param arg
+ * java.lang.String
+ */
+ public void insertData(int offset, String arg) throws DOMException {
+ if (arg == null || arg.length() == 0)
+ return;
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ if (offset < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String source = getSource();
+ if (source == null || source.length() == 0) {
+ if (offset > 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ source = getSource(arg);
+ if (source != null)
+ setTextSource(source);
+ return;
+ }
+
+ StringPair pair = substringSourceExcluded(source, offset, 0);
+ if (pair == null)
+ return; // error
+ StringBuffer buffer = new StringBuffer(source.length() + arg.length());
+ String first = pair.getFirst();
+ if (first != null)
+ buffer.append(first);
+ source = getSource(arg);
+ if (source != null)
+ buffer.append(source);
+ String second = pair.getSecond();
+ if (second != null)
+ buffer.append(second);
+ setTextSource(buffer.toString());
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion insertStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion, IStructuredDocumentRegion nextStructuredDocumentRegion) {
+ if (newStructuredDocumentRegion == null)
+ return null;
+ if (nextStructuredDocumentRegion == null)
+ return appendStructuredDocumentRegion(newStructuredDocumentRegion);
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return null; // error
+
+ if (flatNode == nextStructuredDocumentRegion) {
+ StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer();
+ container.appendStructuredDocumentRegion(newStructuredDocumentRegion);
+ container.appendStructuredDocumentRegion(flatNode);
+ setStructuredDocumentRegion(container);
+ return newStructuredDocumentRegion;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == nextStructuredDocumentRegion) {
+ container.insertStructuredDocumentRegion(newStructuredDocumentRegion, i);
+ return newStructuredDocumentRegion;
+ }
+ }
+ return null; // error
+ }
+
+ return null; // error
+ }
+
+ /**
+ * insertText method
+ *
+ * @param text
+ * org.w3c.dom.Text
+ * @param offset
+ * int
+ */
+ public void insertText(Text newText, int offset) throws DOMException {
+ if (newText == null)
+ return;
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ TextImpl text = (TextImpl) newText;
+ String newSource = text.getSource();
+ if (newSource == null && newSource.length() == 0)
+ return;
+ if (offset < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String source = getSource();
+ if (source == null || source.length() == 0) {
+ if (offset > 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ setTextSource(newSource);
+ return;
+ }
+
+ StringPair pair = substringSourceExcluded(source, offset, 0);
+ if (pair == null)
+ return; // error
+ StringBuffer buffer = new StringBuffer(source.length() + newSource.length());
+ String first = pair.getFirst();
+ if (first != null)
+ buffer.append(first);
+ buffer.append(newSource);
+ String second = pair.getSecond();
+ if (second != null)
+ buffer.append(second);
+ setTextSource(buffer.toString());
+ }
+
+ /**
+ * isCDATAContent method
+ *
+ * @return boolean
+ */
+ public boolean isCDATAContent() {
+ Node parent = getParentNode();
+ if (parent == null || parent.getNodeType() != Node.ELEMENT_NODE)
+ return false;
+ ElementImpl element = (ElementImpl) parent;
+ return element.isCDATAContainer();
+ }
+
+ /**
+ */
+ public boolean isInvalid() {
+ return isInvalid(getStructuredDocumentRegion());
+ }
+
+ /**
+ */
+ private boolean isInvalid(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return false;
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (isInvalid(content))
+ return true;
+ }
+ return false;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ return isInvalid(proxy.getStructuredDocumentRegion());
+ }
+
+ String regionType = StructuredDocumentRegionUtil.getFirstRegionType(flatNode);
+ if (regionType != XMLRegionContext.XML_CONTENT && regionType != JSP_CONTENT && regionType != XMLRegionContext.XML_ENTITY_REFERENCE && regionType != XMLRegionContext.XML_CHAR_REFERENCE && regionType != XMLRegionContext.BLOCK_TEXT && regionType != XMLRegionContext.WHITE_SPACE) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ */
+ boolean isSharingStructuredDocumentRegion(IStructuredDocumentRegion sharedStructuredDocumentRegion) {
+ if (sharedStructuredDocumentRegion == null)
+ return false;
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return false;
+
+ if (flatNode == sharedStructuredDocumentRegion)
+ return false;
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ if (proxy.getStructuredDocumentRegion() == sharedStructuredDocumentRegion)
+ return true;
+ return false;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue;
+ if (content == sharedStructuredDocumentRegion)
+ return false;
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (proxy.getStructuredDocumentRegion() == sharedStructuredDocumentRegion)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ /**
+ */
+ public boolean isWhitespace() {
+ String data = getData();
+ if (data == null)
+ return true;
+ int length = data.length();
+ for (int i = 0; i < length; i++) {
+ if (!Character.isWhitespace(data.charAt(i)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ if (oldStructuredDocumentRegion == null)
+ return null;
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return null; // error
+
+ if (flatNode == oldStructuredDocumentRegion) {
+ setStructuredDocumentRegion(null);
+ return oldStructuredDocumentRegion;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ // removed with proxy
+ setStructuredDocumentRegion(null);
+ return oldStructuredDocumentRegion;
+ }
+ return null; // error
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == oldStructuredDocumentRegion) {
+ container.removeStructuredDocumentRegion(i);
+ if (container.getStructuredDocumentRegionCount() == 1) {
+ // get back to single IStructuredDocumentRegion
+ setStructuredDocumentRegion(container.getStructuredDocumentRegion(0));
+ }
+ return oldStructuredDocumentRegion;
+ }
+
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ // removed with proxy
+ container.removeStructuredDocumentRegion(i);
+ if (container.getStructuredDocumentRegionCount() == 1) {
+ // get back to single IStructuredDocumentRegion
+ setStructuredDocumentRegion(container.getStructuredDocumentRegion(0));
+ }
+ return oldStructuredDocumentRegion;
+ }
+ }
+ }
+ return null; // error
+ }
+
+ return null; // error
+ }
+
+ /**
+ * replaceData method
+ *
+ * @param offset
+ * int
+ * @param count
+ * int
+ * @param arg
+ * java.lang.String
+ */
+ public void replaceData(int offset, int count, String arg) throws DOMException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ if (arg == null || arg.length() == 0) {
+ deleteData(offset, count);
+ return;
+ }
+ if (count == 0) {
+ insertData(offset, arg);
+ return;
+ }
+ if (offset < 0 || count < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String source = getSource();
+ if (source == null || source.length() == 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ StringPair pair = substringSourceExcluded(source, offset, count);
+ if (pair == null)
+ return; // error
+ StringBuffer buffer = new StringBuffer(source.length() + arg.length());
+ String first = pair.getFirst();
+ if (first != null)
+ buffer.append(first);
+ source = getSource(arg);
+ if (source != null)
+ buffer.append(source);
+ String second = pair.getSecond();
+ if (second != null)
+ buffer.append(second);
+ setTextSource(buffer.toString());
+ }
+
+ /**
+ */
+ IStructuredDocumentRegion replaceStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion, IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ if (oldStructuredDocumentRegion == null)
+ return null;
+ if (newStructuredDocumentRegion == null)
+ return removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null)
+ return null; // error
+
+ if (flatNode == oldStructuredDocumentRegion) {
+ setStructuredDocumentRegion(newStructuredDocumentRegion);
+ return oldStructuredDocumentRegion;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ if (newStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) {
+ // proxy must not be nested
+ setStructuredDocumentRegion(newStructuredDocumentRegion);
+ } else {
+ proxy.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ }
+ return oldStructuredDocumentRegion;
+ }
+ return null; // error
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue; // error
+ if (content == oldStructuredDocumentRegion) {
+ container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i);
+ return oldStructuredDocumentRegion;
+ }
+
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ if (newStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) {
+ // proxy must not be nested
+ container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i);
+ } else {
+ proxy.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ }
+ return oldStructuredDocumentRegion;
+ }
+ }
+ }
+ return null; // error
+ }
+
+ return null; // error
+ }
+
+ /**
+ */
+ void resetStructuredDocumentRegions() {
+ String source = getSource();
+ if (source != null && source.length() > 0)
+ this.fSource = source;
+ super.resetStructuredDocumentRegions();
+ }
+
+ /**
+ * getData method
+ *
+ * @return java.lang.String
+ */
+ public void setData(String data) throws DOMException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.fSource = null;
+ super.setData(data);
+ }
+
+ /**
+ */
+ public void setSource(String source) throws InvalidCharacterException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ SourceValidator validator = new SourceValidator(this);
+ if (validator.validateSource(source))
+ setTextSource(source);
+ }
+
+ /**
+ */
+ void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ super.setStructuredDocumentRegion(flatNode);
+ if (flatNode != null)
+ this.fSource = null;
+ }
+
+ /**
+ */
+ public void setTextSource(String source) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ this.fSource = source;
+
+ notifyValueChanged();
+ }
+
+ /**
+ */
+ public void setValueSource(String source) {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+
+ SourceValidator validator = new SourceValidator(this);
+ setTextSource(validator.convertSource(source));
+ }
+
+ /**
+ * splitText method
+ *
+ * @return org.w3c.dom.Text
+ * @param offset
+ * int
+ */
+ public Text splitText(int offset) throws DOMException {
+ if (!isDataEditable()) {
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String());
+ }
+ if (offset < 0) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ int length = getLength();
+ if (offset > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ Document document = getOwnerDocument();
+ if (document == null)
+ return null;
+
+ String source = null;
+ if (offset < length) {
+ int count = length - offset;
+ source = substringSource(offset, count);
+ deleteData(offset, count);
+ }
+ TextImpl text = (TextImpl) document.createTextNode(null);
+ if (source != null)
+ text.setTextSource(source);
+
+ Node parent = getParentNode();
+ if (parent != null)
+ parent.insertBefore(text, getNextSibling());
+
+ return text;
+ }
+
+ /**
+ */
+ Text splitText(IStructuredDocumentRegion nextStructuredDocumentRegion) {
+ if (nextStructuredDocumentRegion == null)
+ return null;
+
+ IStructuredDocumentRegion flatNode = getStructuredDocumentRegion();
+ if (flatNode == null || !(flatNode instanceof StructuredDocumentRegionContainer))
+ return null; // error
+
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ int index = 0;
+ for (; index < count; index++) {
+ if (container.getStructuredDocumentRegion(index) == nextStructuredDocumentRegion)
+ break;
+ }
+ if (index >= count) {
+ // this is the case nextStructuredDocumentRegion is a new
+ // IStructuredDocumentRegion
+ // search gap by offset
+ int offset = nextStructuredDocumentRegion.getStart();
+ for (index = 0; index < count; index++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(index);
+ if (content == null)
+ continue; // error
+ if (content.getStart() >= offset)
+ break;
+ }
+ if (index >= count)
+ return null; // error
+ }
+ if (index == 0)
+ return this; // nothing to do
+
+ Document document = getOwnerDocument();
+ if (document == null)
+ return null; // error
+ Node parent = getParentNode();
+ if (parent == null)
+ return null; // error
+ TextImpl nextText = (TextImpl) document.createTextNode(null);
+ if (nextText == null)
+ return null; // error
+
+ for (; index < count; count--) {
+ nextText.appendStructuredDocumentRegion(container.removeStructuredDocumentRegion(index));
+ }
+
+ // normalize IStructuredDocumentRegion
+ if (index == 1) {
+ setStructuredDocumentRegion(container.getStructuredDocumentRegion(0));
+ }
+
+ parent.insertBefore(nextText, getNextSibling());
+ return nextText;
+ }
+
+ /**
+ * Retruns data for the range
+ */
+ private String substringData(String data, int offset, int count) throws DOMException {
+ // sure offset and count are non-negative
+ if (count == 0)
+ return new String();
+ if (data == null) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ int length = data.length();
+ if (offset > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ int end = offset + count;
+ if (end > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+ return data.substring(offset, end);
+ }
+
+ /**
+ * Returns source for the range specified by: offset: data offset count:
+ * data count
+ */
+ private String substringSource(int offset, int count) throws DOMException {
+ // sure offset and count are non-negative
+ if (this.fSource != null)
+ return substringSource(this.fSource, offset, count);
+
+ String data = super.getData();
+ if (data != null && data.length() > 0) {
+ data = substringData(data, offset, count);
+ if (data == null)
+ return new String();
+ String source = getSource(data);
+ if (source != null)
+ return source;
+ }
+
+ return substringSource(getSource(), offset, count);
+ }
+
+ /**
+ * Returns source for the range specified by: offset: data offset count:
+ * data count
+ */
+ private String substringSource(String source, int offset, int count) throws DOMException {
+ // sure offset and count are non-negative
+ if (count == 0)
+ return new String();
+ if (source == null) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ int length = source.length();
+ int end = offset + count;
+
+ // find character reference
+ int ref = source.indexOf('&');
+ while (ref >= 0) {
+ if (ref >= end)
+ break;
+ int refEnd = source.indexOf(';', ref + 1);
+ if (refEnd > ref + 1) {
+ String name = source.substring(ref + 1, refEnd);
+ if (getCharValue(name) != null) {
+ // found, shift for source offsets
+ int refCount = refEnd - ref;
+ if (ref < offset)
+ offset += refCount;
+ if (ref < end)
+ end += refCount;
+ ref = refEnd;
+ }
+ }
+ ref = source.indexOf('&', ref + 1);
+ }
+
+ if (offset > length || end > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ return source.substring(offset, end);
+ }
+
+ /**
+ * Returns sources before and after the range specified by: offset: data
+ * offset count: data count
+ */
+ private StringPair substringSourceExcluded(String source, int offset, int count) throws DOMException {
+ // sure offset and count are non-negative
+ if (source == null) {
+ if (offset == 0 && count == 0)
+ return new StringPair(null, null);
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ int length = source.length();
+ int end = offset + count;
+
+ // find character reference
+ int ref = source.indexOf('&');
+ while (ref >= 0) {
+ if (ref >= end)
+ break;
+ int refEnd = source.indexOf(';', ref + 1);
+ if (refEnd > ref + 1) {
+ String name = source.substring(ref + 1, refEnd);
+ if (getCharValue(name) != null) {
+ // found, shift for source offsets
+ int refCount = refEnd - ref;
+ if (ref < offset)
+ offset += refCount;
+ if (ref < end)
+ end += refCount;
+ ref = refEnd;
+ }
+ }
+ ref = source.indexOf('&', ref + 1);
+ }
+
+ if (offset > length || end > length) {
+ throw new DOMException(DOMException.INDEX_SIZE_ERR, new String());
+ }
+
+ String first = (offset > 0 ? source.substring(0, offset) : null);
+ String second = (end < length ? source.substring(end, length) : null);
+ return new StringPair(first, second);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java
new file mode 100644
index 0000000000..5000a4d009
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java
@@ -0,0 +1,738 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMDataType;
+import org.eclipse.wst.xml.core.commentelement.impl.CommentElementRegistry;
+import org.eclipse.wst.xml.core.document.DocumentTypeAdapter;
+import org.eclipse.wst.xml.core.document.JSPTag;
+import org.eclipse.wst.xml.core.document.TagAdapter;
+import org.eclipse.wst.xml.core.document.XMLAttr;
+import org.eclipse.wst.xml.core.document.XMLCharEntity;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLGenerator;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+
+
+/**
+ */
+public class XMLGeneratorImpl implements XMLGenerator {
+ private static final String CDATA_CLOSE = "]]>";//$NON-NLS-1$
+ private static final String CDATA_OPEN = "<![CDATA[";//$NON-NLS-1$
+ private static final String COMMENT_CLOSE = "-->";//$NON-NLS-1$
+ private static final String COMMENT_OPEN = "<!--";//$NON-NLS-1$
+ private static final String DOCTYPE_OPEN = "<!DOCTYPE";//$NON-NLS-1$
+ private static final String EMPTY_CLOSE = " />";//$NON-NLS-1$
+ private static final String END_OPEN = "</";//$NON-NLS-1$
+
+ private static XMLGeneratorImpl instance = null;
+ private static final String PI_CLOSE = "?>";//$NON-NLS-1$
+ private static final String PI_OPEN = "<?";//$NON-NLS-1$
+ private static final String PUBLIC_ID = "PUBLIC";//$NON-NLS-1$
+ private static final String SSI_PREFIX = "ssi";//$NON-NLS-1$
+ //private static final String SSI_FEATURE = "SSI";//$NON-NLS-1$
+ private static final String SSI_TOKEN = "#";//$NON-NLS-1$
+ private static final String SYSTEM_ID = "SYSTEM";//$NON-NLS-1$
+ private static final String TAG_CLOSE = ">";//$NON-NLS-1$
+
+ /**
+ */
+ public synchronized static XMLGenerator getInstance() {
+ if (instance == null)
+ instance = new XMLGeneratorImpl();
+ return instance;
+ }
+
+ /**
+ */
+ //private boolean isCommentTag(XMLElement element) {
+ // if (element == null) return false;
+ // DocumentImpl document = (DocumentImpl)element.getOwnerDocument();
+ // if (document == null) return false;
+ // DocumentTypeAdapter adapter = document.getDocumentTypeAdapter();
+ // if (adapter == null) return false;
+ // if (!adapter.hasFeature(SSI_FEATURE)) return false;
+ // String prefix = element.getPrefix();
+ // return (prefix != null && prefix.equals(SSI_PREFIX));
+ //}
+ /**
+ * Helper to modify the tag name in sub-classes
+ */
+ private static void setTagName(Element element, String tagName) {
+ if (element == null || tagName == null)
+ return;
+ ((ElementImpl) element).setTagName(tagName);
+ }
+
+ /**
+ * XMLModelGenerator constructor
+ */
+ private XMLGeneratorImpl() {
+ super();
+ }
+
+ /**
+ */
+ public String generateAttrName(Attr attr) {
+ if (attr == null)
+ return null;
+ String attrName = attr.getName();
+ if (attrName == null)
+ return null;
+ if (attrName.startsWith(JSPTag.TAG_OPEN)) {
+ if (!attrName.endsWith(JSPTag.TAG_CLOSE)) {
+ // close JSP
+ return (attrName + JSPTag.TAG_CLOSE);
+ }
+ }
+ if (((XMLAttr) attr).isGlobalAttr() && CMNodeUtil.getAttributeDeclaration(attr) != null) {
+ switch (getAttrNameCase(attr)) {
+ case DocumentTypeAdapter.UPPER_CASE :
+ attrName = attrName.toUpperCase();
+ break;
+ case DocumentTypeAdapter.LOWER_CASE :
+ attrName = attrName.toLowerCase();
+ break;
+ default :
+ // ASIS_CASE
+ break;
+ }
+ }
+ return attrName;
+ }
+
+ /**
+ */
+ public String generateAttrValue(Attr attr) {
+ return generateAttrValue(attr, (char) 0); // no quote preference
+ }
+
+ /**
+ */
+ public String generateAttrValue(Attr attr, char quote) {
+ if (attr == null)
+ return null;
+ String name = attr.getName();
+ SourceValidator validator = new SourceValidator(attr);
+ String value = validator.convertSource(((XMLNode) attr).getValueSource());
+ if (value == null || value.length() == 0) {
+ if (name != null && name.startsWith(JSPTag.TAG_OPEN))
+ return null;
+ if (isBooleanAttr(attr)) {
+ if (((AttrImpl) attr).isXMLAttr()) {
+ // generate the name as value
+ value = attr.getName();
+ } else {
+ // not to generate '=' and value for HTML boolean
+ return null;
+ }
+ }
+ }
+ return generateAttrValue(value, quote);
+ }
+
+ /**
+ */
+ public String generateAttrValue(String value, char quote) {
+ // assume the valid is already validated not to include both quotes
+ if (quote == '"') {
+ if ((value != null) && (value.indexOf('"') >= 0))
+ quote = '\''; // force
+ } else if (quote == '\'') {
+ if ((value != null) && (value.indexOf('\'') >= 0))
+ quote = '"'; // force
+ } else { // no preference
+ if ((value != null) && (value.indexOf('"') < 0))
+ quote = '"';
+ else
+ quote = '\'';
+ }
+
+ int length = (value == null ? 0 : value.length());
+ StringBuffer buffer = new StringBuffer(length + 2);
+ buffer.append(quote);
+ if (value != null)
+ buffer.append(value);
+ buffer.append(quote);
+ return buffer.toString();
+ }
+
+ /**
+ * generateCDATASection method
+ *
+ * @return java.lang.String
+ * @param comment
+ * org.w3c.dom.CDATASection
+ */
+ public String generateCDATASection(CDATASection cdata) {
+ if (cdata == null)
+ return null;
+
+ String data = cdata.getData();
+ int length = (data != null ? data.length() : 0);
+ StringBuffer buffer = new StringBuffer(length + 16);
+ buffer.append(CDATA_OPEN);
+ if (data != null)
+ buffer.append(data);
+ buffer.append(CDATA_CLOSE);
+ return buffer.toString();
+ }
+
+ /**
+ * generateChild method
+ *
+ * @return java.lang.String
+ * @param org.w3c.dom.Node
+ */
+ public String generateChild(Node parentNode) {
+ if (parentNode == null)
+ return null;
+ if (!parentNode.hasChildNodes())
+ return null;
+
+ StringBuffer buffer = new StringBuffer();
+ for (Node child = parentNode.getFirstChild(); child != null; child = child.getNextSibling()) {
+ String childSource = generateSource(child);
+ if (childSource != null)
+ buffer.append(childSource);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ */
+ public String generateCloseTag(Node node) {
+ if (node == null)
+ return null;
+
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE : {
+ ElementImpl element = (ElementImpl) node;
+ if (element.isCommentTag()) {
+ if (element.isJSPTag())
+ return JSPTag.COMMENT_CLOSE;
+ return COMMENT_CLOSE;
+ }
+ if (element.isJSPTag())
+ return JSPTag.TAG_CLOSE;
+ if (element.isEmptyTag())
+ return EMPTY_CLOSE;
+ return TAG_CLOSE;
+ }
+ case Node.COMMENT_NODE : {
+ CommentImpl comment = (CommentImpl) node;
+ if (comment.isJSPTag())
+ return JSPTag.COMMENT_CLOSE;
+ return COMMENT_CLOSE;
+ }
+ case Node.DOCUMENT_TYPE_NODE :
+ return TAG_CLOSE;
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ return PI_CLOSE;
+ case Node.CDATA_SECTION_NODE :
+ return CDATA_CLOSE;
+ default :
+ break;
+ }
+
+ return null;
+ }
+
+ /**
+ * generateComment method
+ *
+ * @return java.lang.String
+ * @param comment
+ * org.w3c.dom.Comment
+ */
+ public String generateComment(Comment comment) {
+ if (comment == null)
+ return null;
+
+ String data = comment.getData();
+ int length = (data != null ? data.length() : 0);
+ StringBuffer buffer = new StringBuffer(length + 8);
+ CommentImpl impl = (CommentImpl) comment;
+ if (!impl.isJSPTag())
+ buffer.append(COMMENT_OPEN);
+ else
+ buffer.append(JSPTag.COMMENT_OPEN);
+ if (data != null)
+ buffer.append(data);
+ if (!impl.isJSPTag())
+ buffer.append(COMMENT_CLOSE);
+ else
+ buffer.append(JSPTag.COMMENT_CLOSE);
+ return buffer.toString();
+ }
+
+ /**
+ * generateDoctype method
+ *
+ * @return java.lang.String
+ * @param docType
+ * org.w3c.dom.DocumentType
+ */
+ public String generateDoctype(DocumentType docType) {
+ if (docType == null)
+ return null;
+
+ String name = docType.getName();
+ int length = (name != null ? name.length() : 0);
+ StringBuffer buffer = new StringBuffer(length + 16);
+ buffer.append(DOCTYPE_OPEN);
+ buffer.append(' ');
+ if (name != null)
+ buffer.append(name);
+ DocumentTypeImpl dt = (DocumentTypeImpl) docType;
+ String publicID = dt.getPublicId();
+ String systemID = dt.getSystemId();
+ if (publicID != null) {
+ buffer.append(' ');
+ buffer.append(PUBLIC_ID);
+ buffer.append(' ');
+ buffer.append('"');
+ buffer.append(publicID);
+ buffer.append('"');
+ if (systemID != null) {
+ buffer.append(' ');
+ buffer.append('"');
+ buffer.append(systemID);
+ buffer.append('"');
+ }
+ } else {
+ if (systemID != null) {
+ buffer.append(' ');
+ buffer.append(SYSTEM_ID);
+ buffer.append(' ');
+ buffer.append('"');
+ buffer.append(systemID);
+ buffer.append('"');
+ }
+ }
+ buffer.append('>');
+ return buffer.toString();
+ }
+
+ /**
+ * generateElement method
+ *
+ * @return java.lang.String
+ * @param element
+ * Element
+ */
+ public String generateElement(Element element) {
+ if (element == null)
+ return null;
+
+ // if empty tag is preferrable, generate as empty tag
+ ElementImpl impl = (ElementImpl) element;
+ if (impl.preferEmptyTag())
+ impl.setEmptyTag(true);
+
+ StringBuffer buffer = new StringBuffer();
+ String startTag = generateStartTag(element);
+ if (startTag != null)
+ buffer.append(startTag);
+ String child = generateChild(element);
+ if (child != null)
+ buffer.append(child);
+ String endTag = generateEndTag(element);
+ if (endTag != null)
+ buffer.append(endTag);
+ return buffer.toString();
+ }
+
+ /**
+ * generateEndTag method
+ *
+ * @return java.lang.String
+ * @param element
+ * org.w3c.dom.Element
+ */
+ public String generateEndTag(Element element) {
+ if (element == null)
+ return null;
+
+ ElementImpl impl = (ElementImpl) element;
+
+ // first check if tag adapter exists
+ TagAdapter adapter = (TagAdapter) impl.getExistingAdapter(TagAdapter.class);
+ if (adapter != null) {
+ String endTag = adapter.getEndTag(impl);
+ if (endTag != null)
+ return endTag;
+ }
+
+ if (impl.isEmptyTag())
+ return null;
+ if (!impl.isContainer())
+ return null;
+ if (impl.isJSPTag())
+ return JSPTag.TAG_CLOSE;
+
+ String tagName = generateTagName(element);
+ int length = (tagName != null ? tagName.length() : 0);
+ StringBuffer buffer = new StringBuffer(length + 4);
+ buffer.append(END_OPEN);
+ if (tagName != null)
+ buffer.append(tagName);
+ buffer.append('>');
+ return buffer.toString();
+ }
+
+ /**
+ * generateEntityRef method
+ *
+ * @return java.lang.String
+ * @param entityRef
+ * org.w3c.dom.EntityReference
+ */
+ public String generateEntityRef(EntityReference entityRef) {
+ if (entityRef == null)
+ return null;
+
+ String name = entityRef.getNodeName();
+ int length = (name != null ? name.length() : 0);
+ StringBuffer buffer = new StringBuffer(length + 4);
+ buffer.append('&');
+ if (name != null)
+ buffer.append(name);
+ buffer.append(';');
+ return buffer.toString();
+ }
+
+ /**
+ * generatePI method
+ *
+ * @return java.lang.String
+ * @param pi
+ * org.w3c.dom.ProcessingInstruction
+ */
+ public String generatePI(ProcessingInstruction pi) {
+ if (pi == null)
+ return null;
+
+ String target = pi.getTarget();
+ String data = pi.getData();
+ int length = (target != null ? target.length() : 0);
+ if (data != null)
+ length += data.length();
+ StringBuffer buffer = new StringBuffer(length + 8);
+ buffer.append(PI_OPEN);
+ if (target != null)
+ buffer.append(target);
+ buffer.append(' ');
+ if (data != null)
+ buffer.append(data);
+ buffer.append(PI_CLOSE);
+ return buffer.toString();
+ }
+
+ /**
+ * generateSource method
+ *
+ * @return java.lang.String
+ * @param node
+ * org.w3c.dom.Node
+ */
+ public String generateSource(Node node) {
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE :
+ return generateElement((Element) node);
+ case Node.TEXT_NODE :
+ return generateText((Text) node);
+ case Node.COMMENT_NODE :
+ return generateComment((Comment) node);
+ case Node.DOCUMENT_TYPE_NODE :
+ return generateDoctype((DocumentType) node);
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ return generatePI((ProcessingInstruction) node);
+ case Node.CDATA_SECTION_NODE :
+ return generateCDATASection((CDATASection) node);
+ case Node.ENTITY_REFERENCE_NODE :
+ return generateEntityRef((EntityReference) node);
+ default :
+ // DOCUMENT
+ break;
+ }
+ return generateChild(node);
+ }
+
+ /**
+ * generateStartTag method
+ *
+ * @return java.lang.String
+ * @param element
+ * Element
+ */
+ public String generateStartTag(Element element) {
+ if (element == null)
+ return null;
+
+ ElementImpl impl = (ElementImpl) element;
+
+ if (impl.isJSPTag()) {
+ // check if JSP content type and JSP Document
+ XMLDocument document = (XMLDocument) element.getOwnerDocument();
+ if (document != null && document.isJSPType()) {
+ if (document.isJSPDocument() && !impl.hasChildNodes()) {
+ impl.setJSPTag(false);
+ }
+ } else {
+ impl.setJSPTag(false);
+ }
+ }
+ if (impl.isCommentTag() && impl.getExistingAdapter(TagAdapter.class) == null) {
+ CommentElementRegistry registry = CommentElementRegistry.getInstance();
+ registry.setupCommentElement(impl);
+ }
+
+ // first check if tag adapter exists
+ TagAdapter adapter = (TagAdapter) impl.getExistingAdapter(TagAdapter.class);
+ if (adapter != null) {
+ String startTag = adapter.getStartTag(impl);
+ if (startTag != null)
+ return startTag;
+ }
+
+ StringBuffer buffer = new StringBuffer();
+
+ if (impl.isCommentTag()) {
+ if (impl.isJSPTag())
+ buffer.append(JSPTag.COMMENT_OPEN);
+ else
+ buffer.append(COMMENT_OPEN);
+ String tagName = generateTagName(element);
+ if (tagName != null)
+ buffer.append(tagName);
+ } else if (impl.isJSPTag()) {
+ buffer.append(JSPTag.TAG_OPEN);
+ String tagName = generateTagName(element);
+ if (tagName != null)
+ buffer.append(tagName);
+ if (impl.isContainer())
+ return buffer.toString(); // JSP container
+ } else {
+ buffer.append('<');
+ String tagName = generateTagName(element);
+ if (tagName != null)
+ buffer.append(tagName);
+ }
+
+ NamedNodeMap attributes = element.getAttributes();
+ int length = attributes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) attributes.item(i);
+ if (attr == null)
+ continue;
+ buffer.append(' ');
+ String attrName = generateAttrName(attr);
+ if (attrName != null)
+ buffer.append(attrName);
+ String attrValue = generateAttrValue(attr);
+ if (attrValue != null) {
+ // attr name only for HTML boolean and JSP
+ buffer.append('=');
+ buffer.append(attrValue);
+ }
+ }
+
+ String closeTag = generateCloseTag(element);
+ if (closeTag != null)
+ buffer.append(closeTag);
+
+ return buffer.toString();
+ }
+
+ /**
+ */
+ public String generateTagName(Element element) {
+ if (element == null)
+ return null;
+ XMLElement xe = (XMLElement) element;
+ String tagName = element.getTagName();
+ if (tagName == null)
+ return null;
+ if (xe.isJSPTag()) {
+ if (tagName.equals(JSPTag.JSP_EXPRESSION))
+ return JSPTag.EXPRESSION_TOKEN;
+ if (tagName.equals(JSPTag.JSP_DECLARATION))
+ return JSPTag.DECLARATION_TOKEN;
+ if (tagName.equals(JSPTag.JSP_DIRECTIVE))
+ return JSPTag.DIRECTIVE_TOKEN;
+ if (tagName.startsWith(JSPTag.JSP_DIRECTIVE)) {
+ int offset = JSPTag.JSP_DIRECTIVE.length() + 1; // after '.'
+ return (JSPTag.DIRECTIVE_TOKEN + tagName.substring(offset));
+ }
+ return (xe.isCommentTag()) ? tagName : null;
+ } else if (tagName.startsWith(JSPTag.TAG_OPEN)) {
+ if (!tagName.endsWith(JSPTag.TAG_CLOSE)) {
+ // close JSP
+ return (tagName + JSPTag.TAG_CLOSE);
+ }
+ } else if (xe.isCommentTag()) {
+ String prefix = element.getPrefix();
+ if (prefix.equals(SSI_PREFIX)) {
+ return (SSI_TOKEN + element.getLocalName());
+ }
+ } else {
+ if (!xe.isJSPTag() && xe.isGlobalTag() && // global tag
+ CMNodeUtil.getElementDeclaration(xe) != null) {
+ String newName = tagName;
+ switch (getTagNameCase(xe)) {
+ case DocumentTypeAdapter.UPPER_CASE :
+ newName = tagName.toUpperCase();
+ break;
+ case DocumentTypeAdapter.LOWER_CASE :
+ newName = tagName.toLowerCase();
+ break;
+ }
+ if (newName != tagName) {
+ tagName = newName;
+ setTagName(element, tagName);
+ }
+ }
+ }
+ return tagName;
+ }
+
+ /**
+ * generateText method
+ *
+ * @return java.lang.String
+ * @param text
+ * org.w3c.dom.Text
+ */
+ public String generateText(Text text) {
+ if (text == null)
+ return null;
+ TextImpl impl = (TextImpl) text;
+ String source = impl.getTextSource();
+ if (source != null)
+ return source;
+ return generateTextData(text, impl.getData());
+ }
+
+ /**
+ */
+ public String generateTextData(Text text, String data) {
+ if (data == null)
+ return null;
+ if (text == null)
+ return null;
+ TextImpl impl = (TextImpl) text;
+ if (impl.isJSPContent() || impl.isCDATAContent()) {
+ return new SourceValidator(impl).convertSource(data);
+ }
+ String source = data;
+
+ // convert special characters to character entities
+ StringBuffer buffer = null;
+ int offset = 0;
+ int length = data.length();
+ for (int i = 0; i < length; i++) {
+ String name = getCharName(data.charAt(i));
+ if (name == null)
+ continue;
+ if (buffer == null)
+ buffer = new StringBuffer(length + 8);
+ if (i > offset)
+ buffer.append(data.substring(offset, i));
+ buffer.append('&');
+ buffer.append(name);
+ buffer.append(';');
+ offset = i + 1;
+ }
+ if (buffer != null) {
+ if (length > offset)
+ buffer.append(data.substring(offset));
+ source = buffer.toString();
+ }
+
+ if (source == null || source.length() == 0)
+ return null;
+ return source;
+ }
+
+ /**
+ */
+ private int getAttrNameCase(Attr attr) {
+ DocumentImpl document = (DocumentImpl) attr.getOwnerDocument();
+ if (document == null)
+ return DocumentTypeAdapter.STRICT_CASE;
+ DocumentTypeAdapter adapter = document.getDocumentTypeAdapter();
+ if (adapter == null)
+ return DocumentTypeAdapter.STRICT_CASE;
+ return adapter.getAttrNameCase();
+ }
+
+ /**
+ */
+ private String getCharName(char c) {
+ switch (c) {
+ case '<' :
+ return XMLCharEntity.LT_NAME;
+ case '>' :
+ return XMLCharEntity.GT_NAME;
+ case '&' :
+ return XMLCharEntity.AMP_NAME;
+ case '"' :
+ return XMLCharEntity.QUOT_NAME;
+ }
+ return null;
+ }
+
+ /**
+ */
+ private int getTagNameCase(Element element) {
+ DocumentImpl document = (DocumentImpl) element.getOwnerDocument();
+ if (document == null)
+ return DocumentTypeAdapter.STRICT_CASE;
+ DocumentTypeAdapter adapter = document.getDocumentTypeAdapter();
+ if (adapter == null)
+ return DocumentTypeAdapter.STRICT_CASE;
+ return adapter.getTagNameCase();
+ }
+
+ /**
+ */
+ private boolean isBooleanAttr(Attr attr) {
+ if (attr == null)
+ return false;
+ CMAttributeDeclaration decl = CMNodeUtil.getAttributeDeclaration(attr);
+ if (decl == null)
+ return false;
+ CMDataType type = decl.getAttrType();
+ if (type == null)
+ return false;
+ String values[] = type.getEnumeratedValues();
+ if (values == null)
+ return false;
+ return (values.length == 1 && values[0].equals(decl.getAttrName()));
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java
new file mode 100644
index 0000000000..6a799f75f4
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java
@@ -0,0 +1,237 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+/**
+ * XMLModelContext class
+ */
+class XMLModelContext {
+ private Node nextNode = null;
+ private Node parentNode = null;
+
+ // private XMLModelImpl model = null;
+ private Node rootNode = null;
+
+ /**
+ * XMLModelContext constructor
+ *
+ * @param rootNode
+ * org.w3c.dom.Node
+ */
+ XMLModelContext(Node rootNode) {
+ super();
+
+ this.rootNode = rootNode;
+ }
+
+ /**
+ * findEndTag method
+ *
+ * @return org.w3c.dom.Element
+ * @param tagName
+ * java.lang.String
+ */
+ Element findEndTag(String tagName) {
+ if (tagName == null)
+ return null;
+ if (this.parentNode == null)
+ return null;
+
+ for (Node parent = this.parentNode.getParentNode(); parent != null; parent = parent.getParentNode()) {
+ if (parent.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl element = (ElementImpl) parent;
+ if (element.hasEndTag()) {
+ if (element.matchTagName(tagName))
+ return element;
+ // if ancestor element has end tag stop search
+ break;
+ }
+ if (element.getNextSibling() != null)
+ break;
+ }
+
+ return null;
+ }
+
+ /**
+ */
+ Text findNextText() {
+ Node node = this.nextNode;
+ while (node != null) {
+ if (node != this.nextNode && node.getNodeType() == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) node;
+ // skip empty text
+ if (text.getStructuredDocumentRegion() != null)
+ return text;
+ }
+ Node child = node.getFirstChild();
+ if (child != null) {
+ node = child;
+ continue;
+ }
+ while (node != null) {
+ Node next = node.getNextSibling();
+ if (next != null) {
+ node = next;
+ break;
+ }
+ node = node.getParentNode();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * findPreviousText method
+ *
+ * @return org.w3c.dom.Text
+ */
+ Text findPreviousText() {
+ if (this.parentNode == null)
+ return null;
+ Node node = null;
+ if (this.nextNode != null)
+ node = this.nextNode.getPreviousSibling();
+ else
+ node = this.parentNode.getLastChild();
+ if (node == null || node.getNodeType() != Node.TEXT_NODE)
+ return null;
+ return (Text) node;
+ }
+
+ /**
+ * findStartTag method
+ *
+ * @return org.w3c.dom.Element
+ * @param tagName
+ * java.lang.String
+ */
+ Element findStartTag(String tagName, String rootName) {
+ if (tagName == null)
+ return null;
+
+ // check previous for empty content element
+ Node prev = null;
+ if (this.nextNode != null)
+ prev = this.nextNode.getPreviousSibling();
+ else if (this.parentNode != null)
+ prev = this.parentNode.getLastChild();
+ if (prev != null && prev.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) prev;
+ if (!element.hasEndTag() && !element.isEmptyTag() && element.matchTagName(tagName))
+ return element;
+ }
+
+ for (Node parent = this.parentNode; parent != null; parent = parent.getParentNode()) {
+ if (parent.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl element = (ElementImpl) parent;
+ if (element.matchTagName(tagName))
+ return element;
+ if (rootName != null && element.matchTagName(rootName))
+ break;
+ }
+
+ return null;
+ }
+
+ /**
+ * getNextNode method
+ *
+ * @return org.w3c.dom.Node
+ */
+ Node getNextNode() {
+ return this.nextNode;
+ }
+
+ /**
+ * getParentNode method
+ *
+ * @return org.w3c.dom.Node
+ */
+ Node getParentNode() {
+ return this.parentNode;
+ }
+
+ /**
+ * getRootNode method
+ *
+ * @return org.w3c.dom.Node
+ */
+ Node getRootNode() {
+ return this.rootNode;
+ }
+
+ /**
+ * setLast method
+ */
+ void setLast() {
+ if (this.parentNode == null)
+ return;
+ if (this.nextNode != null) {
+ Node prev = this.nextNode.getPreviousSibling();
+ if (prev == null || prev.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ ElementImpl element = (ElementImpl) prev;
+ if (element.hasEndTag() || !element.isContainer() || element.isEmptyTag())
+ return;
+ setParentNode(prev);
+ }
+
+ // find last open parent
+ Node parent = this.parentNode;
+ Node last = parent.getLastChild();
+ while (last != null) {
+ if (last.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl element = (ElementImpl) last;
+ if (element.hasEndTag() || !element.isContainer() || element.isEmptyTag())
+ break;
+ parent = element;
+ last = parent.getLastChild();
+ }
+ if (parent != this.parentNode)
+ setParentNode(parent);
+ }
+
+ /**
+ * setNextNode method
+ *
+ * @param nextNode
+ * org.w3c.dom.Node
+ */
+ void setNextNode(Node nextNode) {
+ this.nextNode = nextNode;
+ if (nextNode == null)
+ return;
+ this.parentNode = nextNode.getParentNode();
+ }
+
+ /**
+ * setParentNode method
+ *
+ * @param parentNode
+ * org.w3c.dom.Node
+ */
+ void setParentNode(Node parentNode) {
+ this.parentNode = parentNode;
+ this.nextNode = null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java
new file mode 100644
index 0000000000..640a164113
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java
@@ -0,0 +1,875 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+import org.eclipse.wst.sse.core.AbstractStructuredModel;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.events.IStructuredDocumentListener;
+import org.eclipse.wst.sse.core.events.NewDocumentEvent;
+import org.eclipse.wst.sse.core.events.NoChangeEvent;
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.RegionsReplacedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentRegionsReplacedEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.Logger;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLGenerator;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.document.XMLModelNotifier;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+/**
+ * XMLModelImpl class
+ */
+public class XMLModelImpl extends AbstractStructuredModel implements IStructuredDocumentListener, XMLModel, DOMImplementation {
+ private static String TRACE_PARSER_MANAGEMENT_EXCEPTION = "parserManagement"; //$NON-NLS-1$
+ private Object active = null;
+ protected DocumentImpl document = null;
+ private XMLGenerator generator = null;
+ private XMLModelNotifier notifier = null;
+ private XMLModelParser parser = null;
+ private boolean refresh = false;
+ private XMLModelUpdater updater = null;
+
+ /**
+ * XMLModelImpl constructor
+ */
+ public XMLModelImpl() {
+ super();
+ this.document = (DocumentImpl) internalCreateDocument();
+ }
+
+ /**
+ * This API allows clients to declare that they are about to make a
+ * "large" change to the model. This change might be in terms of content
+ * or it might be in terms of the model id or base location.
+ *
+ * Note that in the case of embedded calls, notification to listners is
+ * sent only once.
+ *
+ * Note that the client who is making these changes has the responsibility
+ * to restore the models state once finished with the changes. See
+ * getMemento and restoreState.
+ *
+ * The method isModelStateChanging can be used by a client to determine if
+ * the model is already in a change sequence.
+ */
+ public void aboutToChangeModel() {
+ super.aboutToChangeModel();
+ // technically, no need to call beginChanging so often,
+ // since aboutToChangeModel can be nested.
+ // but will leave as is for this release.
+ // see modelChanged, and be sure stays coordinated there.
+ getModelNotifier().beginChanging();
+ }
+
+ public void aboutToReinitializeModel() {
+ XMLModelNotifier notifier = getModelNotifier();
+ notifier.cancelPending();
+ super.aboutToReinitializeModel();
+ }
+
+ /**
+ * attrReplaced method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ * @param newAttr
+ * org.w3c.dom.Attr
+ * @param oldAttr
+ * org.w3c.dom.Attr
+ */
+ protected void attrReplaced(Element element, Attr newAttr, Attr oldAttr) {
+ if (element == null)
+ return;
+ if (getActiveParser() == null) {
+ XMLModelUpdater updater = getModelUpdater();
+ setActive(updater);
+ updater.initialize();
+ updater.replaceAttr(element, newAttr, oldAttr);
+ setActive(null);
+ }
+ getModelNotifier().attrReplaced(element, newAttr, oldAttr);
+ }
+
+ /**
+ * This API allows a client controlled way of notifying all ModelEvent
+ * listners that the model has been changed. This method is a matched pair
+ * to aboutToChangeModel, and must be called after aboutToChangeModel ...
+ * or some listeners could be left waiting indefinitely for the changed
+ * event. So, its suggested that changedModel always be in a finally
+ * clause. Likewise, a client should never call changedModel without
+ * calling aboutToChangeModel first.
+ *
+ * In the case of embedded calls, the notification is just sent once.
+ *
+ */
+ public void changedModel() {
+ // NOTE: the order of 'changedModel' and 'endChanging' is significant.
+ // By calling changedModel first, this basically decrements the
+ // "isChanging" counter
+ // in super class and when zero all listeners to model state events
+ // will be notified
+ // that the model has been changed. 'endChanging' will notify all
+ // deferred adapters.
+ // So, the significance of order is that adapters (and methods they
+ // call)
+ // can count on the state of model "isChanging" to be accurate.
+ // But, remember, that this means the "modelChanged" event can be
+ // received before all
+ // adapters have finished their processing.
+ // NOTE NOTE: The above note is obsolete in fact (though still states
+ // issue correctly).
+ // Due to popular demand, the order of these calls were reversed and
+ // behavior
+ // changed on 07/22/2004.
+ //
+ // see also
+ // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=4302
+ // for motivation for this 'on verge of' call.
+ // this could be improved in future if notifier also used counting
+ // flag to avoid nested calls. If/when changed be sure to check if
+ // aboutToChangeModel needs any changes too.
+ if (isModelChangeStateOnVergeOfEnding()) {
+ // end lock before noticiation loop, since directly or indirectly
+ // we may be "called from foriegn code" during notification.
+ endLock();
+
+ // the notifier is what controls adaper notification, which
+ // should be sent out before the 'modelChanged' event.
+ getModelNotifier().endChanging();
+ }
+ // changedModel handles 'nesting', so only one event sent out
+ // when mulitple calls to 'aboutToChange/Changed'.
+ super.changedModel();
+ handleRefresh();
+ }
+
+ /**
+ * childReplaced method
+ *
+ * @param parentNode
+ * org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ protected void childReplaced(Node parentNode, Node newChild, Node oldChild) {
+ if (parentNode == null)
+ return;
+ if (getActiveParser() == null) {
+ XMLModelUpdater updater = getModelUpdater();
+ setActive(updater);
+ updater.initialize();
+ updater.replaceChild(parentNode, newChild, oldChild);
+ setActive(null);
+ }
+ getModelNotifier().childReplaced(parentNode, newChild, oldChild);
+ }
+
+ /**
+ * Creates an XML <code>Document</code> object of the specified type
+ * with its document element. HTML-only DOM implementations do not need to
+ * implement this method.
+ *
+ * @param namespaceURIThe
+ * namespace URI of the document element to create.
+ * @param qualifiedNameThe
+ * qualified name of the document element to be created.
+ * @param doctypeThe
+ * type of document to be created or <code>null</code>. When
+ * <code>doctype</code> is not <code>null</code>, its
+ * <code>Node.ownerDocument</code> attribute is set to the
+ * document being created.
+ * @return A new <code>Document</code> object.
+ * @exception DOMException
+ * INVALID_CHARACTER_ERR: Raised if the specified qualified
+ * name contains an illegal character. <br>
+ * NAMESPACE_ERR: Raised if the <code>qualifiedName</code>
+ * is malformed, if the <code>qualifiedName</code> has a
+ * prefix and the <code>namespaceURI</code> is
+ * <code>null</code>, or if the
+ * <code>qualifiedName</code> has a prefix that is "xml"
+ * and the <code>namespaceURI</code> is different from "
+ * http://www.w3.org/XML/1998/namespace" .<br>
+ * WRONG_DOCUMENT_ERR: Raised if <code>doctype</code> has
+ * already been used with a different document or was
+ * created from a different implementation.
+ * @since DOM Level 2
+ */
+ public Document createDocument(String namespaceURI, String qualifiedName, DocumentType doctype) throws DOMException {
+ return null;
+ }
+
+ /**
+ * Creates an empty <code>DocumentType</code> node. Entity declarations
+ * and notations are not made available. Entity reference expansions and
+ * default attribute additions do not occur. It is expected that a future
+ * version of the DOM will provide a way for populating a
+ * <code>DocumentType</code>.<br>
+ * HTML-only DOM implementations do not need to implement this method.
+ *
+ * @param qualifiedNameThe
+ * qualified name of the document type to be created.
+ * @param publicIdThe
+ * external subset public identifier.
+ * @param systemIdThe
+ * external subset system identifier.
+ * @return A new <code>DocumentType</code> node with
+ * <code>Node.ownerDocument</code> set to <code>null</code>.
+ * @exception DOMException
+ * INVALID_CHARACTER_ERR: Raised if the specified qualified
+ * name contains an illegal character. <br>
+ * NAMESPACE_ERR: Raised if the <code>qualifiedName</code>
+ * is malformed.
+ * @since DOM Level 2
+ */
+ public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId) throws DOMException {
+ DocumentTypeImpl documentType = new DocumentTypeImpl();
+ documentType.setName(qualifiedName);
+ documentType.setPublicId(publicId);
+ documentType.setSystemId(systemId);
+ return documentType;
+ }
+
+ /**
+ */
+ protected void documentTypeChanged() {
+ if (this.refresh)
+ return;
+ // unlike 'resfresh', 'reinitialize' finishes loop
+ // and flushes remaining notification que before
+ // actually reinitializing.
+ // FUTURE: perhaps all "handleRefresh" should be changed
+ // to "reinit needede"?
+ this.setReinitializeNeeded(true);
+ }
+
+ protected void editableChanged(Node node) {
+ if (node != null) {
+ getModelNotifier().editableChanged(node);
+ }
+ }
+
+ /**
+ */
+ protected void endTagChanged(Element element) {
+ if (element == null)
+ return;
+ if (getActiveParser() == null) {
+ XMLModelUpdater updater = getModelUpdater();
+ setActive(updater);
+ updater.initialize();
+ updater.changeEndTag(element);
+ setActive(null);
+ }
+ getModelNotifier().endTagChanged(element);
+ }
+
+ /**
+ */
+ private XMLModelParser getActiveParser() {
+ if (this.parser == null)
+ return null;
+ if (this.parser != this.active)
+ return null;
+ return this.parser;
+ }
+
+ /**
+ */
+ private XMLModelUpdater getActiveUpdater() {
+ if (this.updater == null)
+ return null;
+ if (this.updater != this.active)
+ return null;
+ return this.updater;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+ */
+ public Object getAdapter(Class adapter) {
+ if (Document.class.equals(adapter))
+ return getDocument();
+ return super.getAdapter(adapter);
+ }
+
+ /**
+ * getDocument method
+ *
+ * @return XMLDocument
+ */
+ public XMLDocument getDocument() {
+ return this.document;
+ }
+
+ public XMLGenerator getGenerator() {
+ if (this.generator == null) {
+ this.generator = XMLGeneratorImpl.getInstance();
+ }
+ return this.generator;
+ }
+
+ /**
+ * getNode method
+ *
+ * @param offset
+ * int
+ */
+ public IndexedRegion getIndexedRegion(int offset) {
+ if (this.document == null)
+ return null;
+ // search in document children
+ XMLNode parent = null;
+ int length = this.document.getEndOffset();
+ if (offset * 2 < length) {
+ // search from the first
+ XMLNode child = (XMLNode) this.document.getFirstChild();
+ while (child != null) {
+ if (child.getEndOffset() <= offset) {
+ child = (XMLNode) child.getNextSibling();
+ continue;
+ }
+ if (child.getStartOffset() > offset) {
+ break;
+ }
+ IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
+ if (startStructuredDocumentRegion != null) {
+ if (startStructuredDocumentRegion.getEnd() > offset)
+ return child;
+ }
+ IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null) {
+ if (endStructuredDocumentRegion.getStart() <= offset)
+ return child;
+ }
+ // dig more
+ parent = child;
+ child = (XMLNode) parent.getFirstChild();
+ }
+ } else {
+ // search from the last
+ XMLNode child = (XMLNode) this.document.getLastChild();
+ while (child != null) {
+ if (child.getStartOffset() > offset) {
+ child = (XMLNode) child.getPreviousSibling();
+ continue;
+ }
+ if (child.getEndOffset() <= offset) {
+ break;
+ }
+ IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion();
+ if (startStructuredDocumentRegion != null) {
+ if (startStructuredDocumentRegion.getEnd() > offset)
+ return child;
+ }
+ IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null) {
+ if (endStructuredDocumentRegion.getStart() <= offset)
+ return child;
+ }
+ // dig more
+ parent = child;
+ child = (XMLNode) parent.getLastChild();
+ }
+ }
+ return parent;
+ }
+
+ /**
+ */
+ public XMLModelNotifier getModelNotifier() {
+ if (this.notifier == null) {
+ this.notifier = new XMLModelNotifierImpl();
+ }
+ return this.notifier;
+ }
+
+ /**
+ */
+ private XMLModelParser getModelParser() {
+ if (this.parser == null) {
+ this.parser = new XMLModelParser(this);
+ }
+ return this.parser;
+ }
+
+ /**
+ */
+ private XMLModelUpdater getModelUpdater() {
+ if (this.updater == null) {
+ this.updater = new XMLModelUpdater(this);
+ }
+ return this.updater;
+ }
+
+ /**
+ */
+ private void handleRefresh() {
+ if (!this.refresh)
+ return;
+ XMLModelNotifier notifier = getModelNotifier();
+ boolean isChanging = notifier.isChanging();
+ if (!isChanging)
+ notifier.beginChanging(true);
+ XMLModelParser parser = getModelParser();
+ setActive(parser);
+ this.document.removeChildNodes();
+ try {
+ parser.replaceStructuredDocumentRegions(getStructuredDocument().getRegionList(), null);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ } finally {
+ setActive(null);
+ if (!isChanging)
+ notifier.endChanging();
+ this.refresh = false;
+ }
+ }
+
+ /**
+ * Test if the DOM implementation implements a specific feature.
+ *
+ * @param featureThe
+ * name of the feature to test (case-insensitive). The values
+ * used by DOM features are defined throughout the DOM Level 2
+ * specifications and listed in the section. The name must be
+ * an XML name. To avoid possible conflicts, as a convention,
+ * names referring to features defined outside the DOM
+ * specification should be made unique by reversing the name of
+ * the Internet domain name of the person (or the organization
+ * that the person belongs to) who defines the feature,
+ * component by component, and using this as a prefix. For
+ * instance, the W3C SVG Working Group defines the feature
+ * "org.w3c.dom.svg".
+ * @param versionThis
+ * is the version number of the feature to test. In Level 2,
+ * the string can be either "2.0" or "1.0". If the version is
+ * not specified, supporting any version of the feature causes
+ * the method to return <code>true</code>.
+ * @return <code>true</code> if the feature is implemented in the
+ * specified version, <code>false</code> otherwise.
+ */
+ public boolean hasFeature(String feature, String version) {
+ if (feature == null)
+ return false;
+ if (version != null) {
+ if (!version.equals("1.0") && !version.equals("2.0")) { //$NON-NLS-2$//$NON-NLS-1$
+ return false;
+ }
+ }
+ if (feature.equalsIgnoreCase("Core")) //$NON-NLS-1$
+ return true; //$NON-NLS-1$
+ if (feature.equalsIgnoreCase("XML")) //$NON-NLS-1$
+ return true; //$NON-NLS-1$
+ return false;
+ }
+
+ /**
+ * createDocument method
+ *
+ * @return org.w3c.dom.Document
+ */
+ protected Document internalCreateDocument() {
+ DocumentImpl document = new DocumentImpl();
+ document.setModel(this);
+ return document;
+ }
+
+ boolean isReparsing() {
+ return (active != null);
+ }
+
+ /**
+ * nameChanged method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ protected void nameChanged(Node node) {
+ if (node == null)
+ return;
+ if (getActiveParser() == null) {
+ XMLModelUpdater updater = getModelUpdater();
+ setActive(updater);
+ updater.initialize();
+ updater.changeName(node);
+ setActive(null);
+ }
+ // notification is already sent
+ }
+
+ /**
+ * newModel method
+ *
+ * @param structuredDocumentEvent
+ * com.ibm.sed.structuredDocument.impl.events.NewModelEvent
+ */
+ public void newModel(NewDocumentEvent structuredDocumentEvent) {
+ if (structuredDocumentEvent == null)
+ return;
+ IStructuredDocument structuredDocument = structuredDocumentEvent.getStructuredDocument();
+ if (structuredDocument == null)
+ return;
+ // this should not happen, but for the case
+ if (structuredDocument != getStructuredDocument())
+ setStructuredDocument(structuredDocument);
+ IStructuredDocumentRegionList flatNodes = structuredDocument.getRegionList();
+ if (flatNodes == null)
+ return;
+ if (this.document == null)
+ return; // being constructed
+ XMLModelUpdater updater = getActiveUpdater();
+ if (updater != null) { // being updated
+ try {
+ updater.replaceStructuredDocumentRegions(flatNodes, null);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ }
+ // // for new model, we might need to
+ // // re-init, e.g. if someone calls setText
+ // // on an existing model
+ // checkForReinit();
+ return;
+ }
+ XMLModelNotifier notifier = getModelNotifier();
+ boolean isChanging = notifier.isChanging();
+ // call even if changing to notify doing new model
+ getModelNotifier().beginChanging(true);
+ XMLModelParser parser = getModelParser();
+ setActive(parser);
+ this.document.removeChildNodes();
+ try {
+ parser.replaceStructuredDocumentRegions(flatNodes, null);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ // meaningless to refresh, because the result might be the same
+ } finally {
+ setActive(null);
+ if (!isChanging) {
+ getModelNotifier().endChanging();
+ }
+ // ignore refresh
+ this.refresh = false;
+ }
+ // checkForReinit();
+ }
+
+ /**
+ */
+ public void noChange(NoChangeEvent event) {
+ XMLModelUpdater updater = getActiveUpdater();
+ if (updater != null) { // being updated
+ // cleanup updater staffs
+ try {
+ updater.replaceStructuredDocumentRegions(null, null);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ }
+ // I guess no chanage means the model could not need re-init
+ //checkForReinit();
+ return;
+ }
+ }
+
+ /**
+ * nodesReplaced method
+ *
+ * @param event
+ * com.ibm.sed.structuredDocument.impl.events.NodesReplacedElement
+ */
+ public void nodesReplaced(StructuredDocumentRegionsReplacedEvent event) {
+ if (event == null)
+ return;
+ IStructuredDocumentRegionList oldStructuredDocumentRegions = event.getOldStructuredDocumentRegions();
+ IStructuredDocumentRegionList newStructuredDocumentRegions = event.getNewStructuredDocumentRegions();
+ XMLModelUpdater updater = getActiveUpdater();
+ if (updater != null) { // being updated
+ try {
+ updater.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
+ } catch (Exception ex) {
+ if (ex.getClass().equals(StructuredDocumentRegionManagementException.class)) {
+ Logger.traceException(TRACE_PARSER_MANAGEMENT_EXCEPTION, ex);
+ } else {
+ Logger.logException(ex);
+ }
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ }
+ //checkForReinit();
+ return;
+ }
+ XMLModelNotifier notifier = getModelNotifier();
+ boolean isChanging = notifier.isChanging();
+ if (!isChanging)
+ notifier.beginChanging();
+ XMLModelParser parser = getModelParser();
+ setActive(parser);
+ try {
+ parser.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ if (!isChanging) {
+ notifier.endChanging();
+ handleRefresh();
+ }
+ }
+
+ }
+
+ /**
+ * regionChanged method
+ *
+ * @param structuredDocumentEvent
+ * com.ibm.sed.structuredDocument.impl.events.RegionChangedEvent
+ */
+ public void regionChanged(RegionChangedEvent event) {
+ if (event == null)
+ return;
+ IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
+ if (flatNode == null)
+ return;
+ ITextRegion region = event.getRegion();
+ if (region == null)
+ return;
+ XMLModelUpdater updater = getActiveUpdater();
+ if (updater != null) { // being updated
+ try {
+ updater.changeRegion(flatNode, region);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ }
+ // checkForReinit();
+ return;
+ }
+ XMLModelNotifier notifier = getModelNotifier();
+ boolean isChanging = notifier.isChanging();
+ if (!isChanging)
+ notifier.beginChanging();
+ XMLModelParser parser = getModelParser();
+ setActive(parser);
+ try {
+ parser.changeRegion(flatNode, region);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ if (!isChanging) {
+ notifier.endChanging();
+ handleRefresh();
+ }
+ }
+ // checkForReinit();
+ }
+
+ /**
+ * regionsReplaced method
+ *
+ * @param event
+ * com.ibm.sed.structuredDocument.impl.events.RegionReplacedEvent
+ */
+ public void regionsReplaced(RegionsReplacedEvent event) {
+ if (event == null)
+ return;
+ IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion();
+ if (flatNode == null)
+ return;
+ ITextRegionList oldRegions = event.getOldRegions();
+ ITextRegionList newRegions = event.getNewRegions();
+ if (oldRegions == null && newRegions == null)
+ return;
+ XMLModelUpdater updater = getActiveUpdater();
+ if (updater != null) { // being updated
+ try {
+ updater.replaceRegions(flatNode, newRegions, oldRegions);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ }
+ // checkForReinit();
+ return;
+ }
+ XMLModelNotifier notifier = getModelNotifier();
+ boolean isChanging = notifier.isChanging();
+ if (!isChanging)
+ notifier.beginChanging();
+ XMLModelParser parser = getModelParser();
+ setActive(parser);
+ try {
+ parser.replaceRegions(flatNode, newRegions, oldRegions);
+ } catch (Exception ex) {
+ Logger.logException(ex);
+ this.refresh = true;
+ handleRefresh();
+ } finally {
+ setActive(null);
+ if (!isChanging) {
+ notifier.endChanging();
+ handleRefresh();
+ }
+ }
+ // checkForReinit();
+ }
+
+ /**
+ */
+ public void releaseFromEdit() {
+ if (!isShared()) {
+ //this.document.releaseStyleSheets();
+ this.document.releaseDocumentType();
+ }
+ super.releaseFromEdit();
+ }
+
+ /**
+ */
+ public void releaseFromRead() {
+ if (!isShared()) {
+ //this.document.releaseStyleSheets();
+ this.document.releaseDocumentType();
+ }
+ super.releaseFromRead();
+ }
+
+ /**
+ */
+ private void setActive(Object active) {
+ this.active = active;
+ // side effect
+ // when ever becomes active, besure tagNameCache is cleared
+ // (and not used)
+ if (active == null) {
+ document.activateTagNameCache(true);
+ } else {
+ document.activateTagNameCache(false);
+ }
+
+ }
+
+ /**
+ */
+ public void setGenerator(XMLGenerator generator) {
+ this.generator = generator;
+ }
+
+ /**
+ */
+ public void setModelNotifier(XMLModelNotifier notifier) {
+ this.notifier = notifier;
+ }
+
+ /**
+ */
+ public void setModelParser(XMLModelParser parser) {
+ this.parser = parser;
+ }
+
+ /**
+ */
+ public void setModelUpdater(XMLModelUpdater updater) {
+ this.updater = updater;
+ }
+
+ /**
+ * setStructuredDocument method
+ *
+ * @param structuredDocument
+ * com.ibm.sed.structuredDocument.IStructuredDocument
+ */
+ public void setStructuredDocument(IStructuredDocument structuredDocument) {
+ IStructuredDocument oldStructuredDocument = super.getStructuredDocument();
+ if (structuredDocument == oldStructuredDocument)
+ return; // nothing to do
+ if (oldStructuredDocument != null)
+ oldStructuredDocument.removeDocumentChangingListener(this);
+ super.setStructuredDocument(structuredDocument);
+ if (structuredDocument.getLength() > 0) {
+ newModel(new NewDocumentEvent(structuredDocument, this));
+ }
+ if (structuredDocument != null)
+ structuredDocument.addDocumentChangingListener(this);
+ }
+
+ /**
+ */
+ protected void startTagChanged(Element element) {
+ if (element == null)
+ return;
+ if (getActiveParser() == null) {
+ XMLModelUpdater updater = getModelUpdater();
+ setActive(updater);
+ updater.initialize();
+ updater.changeStartTag(element);
+ setActive(null);
+ }
+ getModelNotifier().startTagChanged(element);
+ }
+
+ /**
+ * valueChanged method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ protected void valueChanged(Node node) {
+ if (node == null)
+ return;
+ if (getActiveParser() == null) {
+ XMLModelUpdater updater = getModelUpdater();
+ setActive(updater);
+ updater.initialize();
+ updater.changeValue(node);
+ setActive(null);
+ }
+ getModelNotifier().valueChanged(node);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java
new file mode 100644
index 0000000000..4146e0c5af
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java
@@ -0,0 +1,469 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.xml.core.Logger;
+import org.eclipse.wst.xml.core.document.XMLModelNotifier;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+public class XMLModelNotifierImpl implements XMLModelNotifier {
+
+ /* end: for debugging only */
+ private class NotifyEvent {
+ Object changedFeature;
+ boolean discarded;
+ Object newValue;
+ // note: don't initialize instance variables, since
+ // that causes double assignments, and lots of these are created.
+ INodeNotifier notifier;
+ Object oldValue;
+ int pos;
+ String reason;
+ int type;
+
+ NotifyEvent(INodeNotifier notifier, int type, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ this.notifier = notifier;
+ this.type = type;
+ this.changedFeature = changedFeature;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ this.pos = pos;
+ this.reason = ""; //$NON-NLS-1$
+ }
+ }
+
+ private final static String ADDED_THEN_REMOVED = "Discard: Added then removed rule"; //$NON-NLS-1$
+ private final static boolean fOptimizeDeferred = true;
+ private final static boolean fOptimizeDeferredAccordingToParentAdded = true;
+ private final static boolean fOptimizeDeferredAccordingToParentRemoved = true;
+ private final static String PARENT_IS_ADDED = "Disarded: Parent has just been added"; //$NON-NLS-1$
+ /* start: for debugging only */
+ private final static String PARENT_IS_REMOVED_TOO = "Discard: Parent was removed too"; //$NON-NLS-1$
+ private final static String PARENT_IS_REPARENTED = "Not Discard: Parent was removed so this implies reparenting"; //$NON-NLS-1$
+ private Node changedRoot = null;
+
+ private boolean changing = false;
+ private boolean doingNewModel = false;
+ private Vector events = null;
+ private boolean flushing = false;
+
+ /**
+ */
+ public XMLModelNotifierImpl() {
+ super();
+ }
+
+ /**
+ * attrReplaced method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ * @param newAttr
+ * org.w3c.dom.Attr
+ * @param oldAttr
+ * org.w3c.dom.Attr
+ */
+ public void attrReplaced(Element element, Attr newAttr, Attr oldAttr) {
+ if (element == null)
+ return;
+ Attr attr = null;
+ String oldValue = null;
+ String newValue = null;
+ if (oldAttr != null) {
+ attr = oldAttr;
+ oldValue = oldAttr.getValue();
+ }
+ if (newAttr != null) {
+ attr = newAttr;
+ newValue = newAttr.getValue();
+ }
+ XMLNode notifier = (XMLNode) element;
+ int offset = notifier.getStartOffset();
+ notify(notifier, INodeNotifier.CHANGE, attr, oldValue, newValue, offset);
+ propertyChanged(notifier);
+ }
+
+ /**
+ */
+ public void beginChanging() {
+ this.changing = true;
+ }
+
+ /**
+ */
+ public void beginChanging(boolean newModel) {
+ beginChanging();
+ this.doingNewModel = newModel;
+ }
+
+ /**
+ * @see com.ibm.sed.model.xml.XMLModelNotifier#cancelPending()
+ */
+ public void cancelPending() {
+ // we don't want to change the size of this array, since
+ // the array may be being processed, in the defferred notification
+ // loop, but we can signal that all
+ // should be discarded, so any remaining ones will be ignored.
+ if (this.events != null) {
+ Iterator iterator = this.events.iterator();
+ while (iterator.hasNext()) {
+ NotifyEvent event = (NotifyEvent) iterator.next();
+ event.discarded = true;
+ }
+ }
+ // this cancel is presumably being called as a function of
+ // "reinitiailization" so we can ignore changes to the
+ // old root, and changes to the new one will be triggered during
+ // reinitialization.
+ changedRoot = null;
+ }
+
+ /**
+ * childReplaced method
+ *
+ * @param parentNode
+ * org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ public void childReplaced(Node parentNode, Node newChild, Node oldChild) {
+ if (parentNode == null)
+ return;
+ XMLNode notifier = (XMLNode) parentNode;
+ int type = INodeNotifier.CHANGE;
+ if (newChild == null)
+ type = INodeNotifier.REMOVE;
+ else if (oldChild == null)
+ type = INodeNotifier.ADD;
+ int offset = notifier.getStartOffset();
+ notify(notifier, type, oldChild, oldChild, newChild, offset);
+ structureChanged(notifier);
+ }
+
+ public void editableChanged(Node node) {
+ if (node == null)
+ return;
+ XMLNode notifier = (XMLNode) node;
+ int offset = notifier.getStartOffset();
+ notify(notifier, INodeNotifier.CHANGE, null, null, null, offset);
+ propertyChanged(notifier);
+ }
+
+ /**
+ */
+ public void endChanging() {
+ this.doingNewModel = false;
+ if (!this.changing)
+ return; // avoid nesting calls
+ notifyDeferred();
+ if (this.changedRoot != null) {
+ notifyStructureChanged(this.changedRoot);
+ if (Debug.debugNotifyDeferred) {
+ String p = this.changedRoot.getNodeName();
+ System.out.println("Deferred STRUCUTRE_CHANGED: " + p); //$NON-NLS-1$
+ }
+ this.changedRoot = null;
+ }
+ this.changing = false;
+ }
+
+ /**
+ */
+ public void endTagChanged(Element element) {
+ if (element == null)
+ return;
+ XMLNode notifier = (XMLNode) element;
+ int offset = notifier.getStartOffset();
+ notify(notifier, INodeNotifier.CHANGE, null, null, null, offset);
+ propertyChanged(element);
+ }
+
+ /**
+ */
+ public boolean hasChanged() {
+ return (this.events != null);
+ }
+
+ /**
+ */
+ public boolean isChanging() {
+ return this.changing;
+ }
+
+ /**
+ */
+ private void notify(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ if (notifier == null)
+ return;
+ if (this.changing && !this.flushing) {
+ // defer notification
+ if (this.events == null)
+ this.events = new Vector();
+ // we do not defer anything if we are doing a new Model,
+ // except for the document event, since all others are
+ // trivial and not needed at that initial point.
+ // But even for that one document event, in the new model case,
+ // it is still important to defer it.
+ if ((!doingNewModel) || (((Node) notifier).getNodeType() == Node.DOCUMENT_NODE)) {
+ this.events.addElement(new NotifyEvent(notifier, eventType, changedFeature, oldValue, newValue, pos));
+ }
+ return;
+ }
+ try {
+ // Its important to "keep going" if exception occurs, since this
+ // notification
+ // comes in between "about to change" and "changed" events. We do
+ // log, however,
+ // since would indicate a program error.
+ notifier.notify(eventType, changedFeature, oldValue, newValue, pos);
+ } catch (Exception e) {
+ Logger.logException("A structured model client threw following exception during adapter notification (" + INodeNotifier.EVENT_TYPE_STRINGS[eventType] + " )", e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ */
+ private void notifyDeferred() {
+ if (this.events == null)
+ return;
+ if (this.flushing)
+ return;
+ this.flushing = true; // force notification
+ int count = this.events.size();
+ for (int i = 0; i < count; i++) {
+ NotifyEvent event = (NotifyEvent) this.events.elementAt(i);
+ if (event == null)
+ continue; // error
+ if (event.discarded)
+ continue;
+ if (!doingNewModel && fOptimizeDeferred) {
+ // check redundant events (no need to check if doing NewModel,
+ // since
+ // shouldn't be redunancies)
+ if (event.type == INodeNotifier.ADD) {
+ for (int n = i + 1; n < count; n++) {
+ NotifyEvent next = (NotifyEvent) this.events.elementAt(n);
+ if (next == null)
+ continue; // error
+ if (next.type == INodeNotifier.REMOVE && next.oldValue == event.newValue) {
+ // Added then removed later, discard both
+ event.discarded = true;
+ next.discarded = true;
+ if (Debug.debugNotifyDeferred) {
+ event.reason = event.reason + ADDED_THEN_REMOVED + "(see " + n + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ next.reason = next.reason + ADDED_THEN_REMOVED + "(see " + i + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ break;
+ }
+ }
+ if (event.discarded)
+ continue;
+ if (fOptimizeDeferredAccordingToParentAdded) {
+ for (int p = 0; p < i; p++) {
+ NotifyEvent prev = (NotifyEvent) this.events.elementAt(p);
+ if (prev == null)
+ continue; // error
+ if (prev.type == INodeNotifier.REMOVE && prev.oldValue == event.notifier) {
+ // parent is reparented, do not discard
+ if (Debug.debugNotifyDeferred) {
+ event.reason = event.reason + PARENT_IS_REPARENTED + "(see " + p + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ break;
+ } else if (prev.type == INodeNotifier.ADD && prev.newValue == event.notifier) {
+ // parent has been added, discard this
+ event.discarded = true;
+ if (Debug.debugNotifyDeferred) {
+ event.reason = event.reason + PARENT_IS_ADDED + "(see " + p + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ break;
+ }
+ }
+ if (event.discarded)
+ continue;
+ }
+ } else if (event.type == INodeNotifier.REMOVE) {
+ if (fOptimizeDeferredAccordingToParentRemoved) {
+ for (int n = i + 1; n < count; n++) {
+ NotifyEvent next = (NotifyEvent) this.events.elementAt(n);
+ if (next == null)
+ continue; // error
+ if (next.type == INodeNotifier.REMOVE) {
+ if (next.oldValue == event.notifier) {
+ // parent will be removed, discard this
+ event.discarded = true;
+ if (Debug.debugNotifyDeferred) {
+ event.reason = event.reason + PARENT_IS_REMOVED_TOO + "(see " + n + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ break;
+ }
+ }
+ }
+ if (event.discarded)
+ continue;
+ }
+ }
+ }
+ notify(event.notifier, event.type, event.changedFeature, event.oldValue, event.newValue, event.pos);
+ }
+ if (Debug.debugNotifyDeferred) {
+ for (int l = 0; l < count; l++) {
+ NotifyEvent event = (NotifyEvent) this.events.elementAt(l);
+ Object o = null;
+ String t = null;
+ if (event.type == INodeNotifier.ADD) {
+ o = event.newValue;
+ t = " + "; //$NON-NLS-1$
+ } else if (event.type == INodeNotifier.REMOVE) {
+ o = event.oldValue;
+ t = " - "; //$NON-NLS-1$
+ }
+ if (o instanceof Element) {
+ String p = ((Node) event.notifier).getNodeName();
+ String c = ((Node) o).getNodeName();
+ String d = (event.discarded ? "! " : " "); //$NON-NLS-1$ //$NON-NLS-2$
+ System.out.println(d + p + t + c);
+ }
+ }
+ }
+ this.flushing = false;
+ this.events = null;
+ }
+
+ /**
+ */
+ private void notifyStructureChanged(Node root) {
+ if (root == null)
+ return;
+ INodeNotifier notifier = (INodeNotifier) root;
+ try {
+ // Its important to "keep going" if exception occurs, since this
+ // notification
+ // comes in between "about to change" and "changed" events. We do
+ // log, however,
+ // since would indicate a program error.
+ notifier.notify(INodeNotifier.STRUCTURE_CHANGED, null, null, null, -1);
+ } catch (Exception e) {
+ Logger.logException("A structured model client threw following exception during adapter notification (" + INodeNotifier.EVENT_TYPE_STRINGS[INodeNotifier.STRUCTURE_CHANGED] + " )", e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ }
+
+ /**
+ */
+ public void propertyChanged(Node node) {
+ }
+
+ /**
+ * @param node
+ */
+ private void setCommonRootIfNeeded(Node node) {
+ // defer notification
+ if (this.changedRoot == null) {
+ this.changedRoot = node;
+ } else {
+ // tiny optimization: if previous commonAncestor (changedRoot) is
+ // already 'document',
+ // or if already equal to this 'node',
+ // then no need to re-calculate
+ if (changedRoot.getNodeType() != Node.DOCUMENT_NODE && changedRoot != node) {
+ Node common = ((NodeImpl) this.changedRoot).getCommonAncestor(node);
+ if (common != null)
+ this.changedRoot = common;
+ else
+ this.changedRoot = node;
+ }
+ }
+ }
+
+ /**
+ */
+ public void startTagChanged(Element element) {
+ if (element == null)
+ return;
+ XMLNode notifier = (XMLNode) element;
+ int offset = notifier.getStartOffset();
+ notify(notifier, INodeNotifier.CHANGE, null, null, null, offset);
+ propertyChanged(element);
+ }
+
+ /**
+ */
+ public void structureChanged(Node node) {
+ if (node == null)
+ return;
+ if (isChanging()) {
+ setCommonRootIfNeeded(node);
+ if (Debug.debugNotifyDeferred) {
+ String p = this.changedRoot.getNodeName();
+ System.out.println("requested STRUCUTRE_CHANGED: " + p); //$NON-NLS-1$
+ }
+ return;
+ }
+ if (Debug.debugNotifyDeferred) {
+ String p = node.getNodeName();
+ System.out.println("STRUCUTRE_CHANGED: " + p); //$NON-NLS-1$
+ }
+ notifyStructureChanged(node);
+ }
+
+ /**
+ * valueChanged method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ public void valueChanged(Node node) {
+ if (node == null)
+ return;
+ XMLNode notifier = null;
+ if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
+ Attr attr = (Attr) node;
+ notifier = (XMLNode) attr.getOwnerElement();
+ // TODO_dmw: experimental: changed 06/29/2004 to send "strucuture
+ // changed" even for attribute value changes
+ // there are pros and cons to considering attribute value
+ // "structure changed". Will (re)consider
+ // setCommonRootIfNeeded(notifier);
+ if (notifier == null)
+ return;
+ String value = attr.getValue();
+ int offset = notifier.getStartOffset();
+ notify(notifier, INodeNotifier.CHANGE, attr, null, value, offset);
+ } else {
+ // note: we do not send structured changed event for content
+ // changed
+ notifier = (XMLNode) node;
+ String value = node.getNodeValue();
+ int offset = notifier.getStartOffset();
+ notify(notifier, INodeNotifier.CHANGE, null, null, value, offset);
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ XMLNode parent = (XMLNode) node.getParentNode();
+ if (parent != null) {
+ notify(parent, INodeNotifier.CONTENT_CHANGED, node, null, value, offset);
+ }
+ }
+ }
+ propertyChanged(notifier);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java
new file mode 100644
index 0000000000..7d64743d9a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java
@@ -0,0 +1,2365 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.commentelement.impl.CommentElementConfiguration;
+import org.eclipse.wst.xml.core.commentelement.impl.CommentElementRegistry;
+import org.eclipse.wst.xml.core.document.JSPTag;
+import org.eclipse.wst.xml.core.document.XMLDocument;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+
+/**
+ * XMLModelParser
+ */
+public class XMLModelParser implements org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts {
+ private ModelParserAdapter adapter = null;
+ private XMLModelContext context = null;
+ private DocumentImpl document = null;
+
+ private XMLModelImpl model = null;
+
+ /**
+ */
+ protected XMLModelParser(XMLModelImpl model) {
+ super();
+
+ if (model != null) {
+ this.model = model;
+ this.document = (DocumentImpl) model.getDocument();
+ if (this.document != null) {
+ this.adapter = (ModelParserAdapter) this.document.getAdapterFor(ModelParserAdapter.class);
+ }
+ }
+ }
+
+ /**
+ */
+ protected boolean canBeImplicitTag(Element element) {
+ if (this.adapter != null) {
+ return this.adapter.canBeImplicitTag(element);
+ }
+ return false;
+ }
+
+ /**
+ */
+ protected boolean canBeImplicitTag(Element element, Node child) {
+ if (this.adapter != null) {
+ return this.adapter.canBeImplicitTag(element, child);
+ }
+ return false;
+ }
+
+ /**
+ */
+ protected boolean canContain(Element element, Node child) {
+ if (element == null || child == null)
+ return false;
+ ElementImpl impl = (ElementImpl) element;
+ if (impl.isEndTag())
+ return false; // invalid (floating) end tag
+ if (!impl.isContainer())
+ return false;
+ if (child.getNodeType() != Node.TEXT_NODE) {
+ if (impl.isJSPContainer() || impl.isCDATAContainer()) {
+ // accepts only Text child
+ return false;
+ }
+ }
+ if (this.adapter != null) {
+ return this.adapter.canContain(element, child);
+ }
+ return true;
+ }
+
+ /**
+ */
+ private void changeAttrEqual(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return;
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return;
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return;
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
+ // just notify the change instead of setting data
+ ProcessingInstructionImpl pi = (ProcessingInstructionImpl) node;
+ pi.notifyValueChanged();
+ }
+ return;
+ }
+ // actually, do nothing
+ }
+
+ /**
+ * changeAttrName method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ * @param region
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ private void changeAttrName(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return;
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return;
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return;
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
+ // just notify the change instead of setting data
+ ProcessingInstructionImpl pi = (ProcessingInstructionImpl) node;
+ pi.notifyValueChanged();
+ }
+ return;
+ }
+
+ ElementImpl element = (ElementImpl) node;
+ NamedNodeMap attributes = element.getAttributes();
+ if (attributes == null)
+ return;
+ int length = attributes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) attributes.item(i);
+ if (attr == null)
+ continue;
+ if (attr.getNameRegion() != region)
+ continue;
+
+ String name = flatNode.getText(region);
+ attr.setName(name);
+ break;
+ }
+ }
+
+ /**
+ * changeAttrValue method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ * @param region
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ private void changeAttrValue(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return;
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return;
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return;
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
+ // just notify the change instead of setting data
+ ProcessingInstructionImpl pi = (ProcessingInstructionImpl) node;
+ pi.notifyValueChanged();
+ }
+ return;
+ }
+
+ ElementImpl element = (ElementImpl) node;
+ NamedNodeMap attributes = element.getAttributes();
+ if (attributes == null)
+ return;
+ int length = attributes.getLength();
+ for (int i = 0; i < length; i++) {
+ AttrImpl attr = (AttrImpl) attributes.item(i);
+ if (attr == null)
+ continue;
+ if (attr.getValueRegion() != region)
+ continue;
+ // just notify the change instead of setting value
+ attr.notifyValueChanged();
+ break;
+ }
+ }
+
+ /**
+ * changeData method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ * @param region
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ private void changeData(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return;
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return;
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return;
+ switch (node.getNodeType()) {
+ case Node.TEXT_NODE : {
+ TextImpl text = (TextImpl) node;
+ if (text.isSharingStructuredDocumentRegion(flatNode)) {
+ // has consecutive text sharing IStructuredDocumentRegion
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+ this.context.setNextNode(node);
+ cleanupText();
+ break;
+ }
+ case Node.CDATA_SECTION_NODE :
+ case Node.PROCESSING_INSTRUCTION_NODE :
+ break;
+ case Node.COMMENT_NODE :
+ case Node.ELEMENT_NODE :
+ // comment tag
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ default :
+ return;
+ }
+
+ // just notify the change instead of setting data
+ NodeImpl impl = (NodeImpl) node;
+ impl.notifyValueChanged();
+ }
+
+ /**
+ */
+ private void changeEndTag(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return; // error
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return; // error
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return; // error
+
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+
+ // check if change is only for close tag
+ if (newRegions != null) {
+ Iterator e = newRegions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_CLOSE)
+ continue;
+
+ // other region has changed
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+ }
+ if (oldRegions != null) {
+ Iterator e = oldRegions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_CLOSE)
+ continue;
+
+ // other region has changed
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+ }
+
+ // change for close tag has no impact
+ // do nothing
+ }
+
+ /**
+ * changeRegion method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ * @param region
+ * com.ibm.sed.structuredDocument.ITextRegion
+ */
+ void changeRegion(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ if (flatNode == null || region == null)
+ return;
+ if (this.document == null)
+ return;
+ this.context = new XMLModelContext(this.document);
+
+ // optimize typical cases
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_CONTENT || regionType == XMLRegionContext.XML_COMMENT_TEXT || regionType == XMLRegionContext.XML_CDATA_TEXT || regionType == XMLRegionContext.BLOCK_TEXT || regionType == JSP_CONTENT) {
+ changeData(flatNode, region);
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) {
+ changeAttrName(flatNode, region);
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+ changeAttrValue(flatNode, region);
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+ changeAttrEqual(flatNode, region);
+ } else if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME || regionType == JSP_DIRECTIVE_NAME) {
+ changeTagName(flatNode, region);
+ } else {
+ changeStructuredDocumentRegion(flatNode);
+ }
+ }
+
+ /**
+ */
+ private void changeStartTag(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return; // error
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return; // error
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return; // error
+
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+ ElementImpl element = (ElementImpl) node;
+
+ // check if changes are only for attributes and close tag
+ boolean tagNameUnchanged = false;
+ if (newRegions != null) {
+ Iterator e = newRegions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)
+ continue;
+ if (regionType == XMLRegionContext.XML_TAG_CLOSE) {
+ // change from empty tag may have impact on structure
+ if (!element.isEmptyTag())
+ continue;
+ } else if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME || regionType == JSP_DIRECTIVE_NAME) {
+ String oldTagName = element.getTagName();
+ String newTagName = flatNode.getText(region);
+ if (oldTagName != null && newTagName != null && oldTagName.equals(newTagName)) {
+ // the tag name is unchanged
+ tagNameUnchanged = true;
+ continue;
+ }
+ }
+
+ // other region has changed
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+ }
+ if (oldRegions != null) {
+ Iterator e = oldRegions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)
+ continue;
+ if (regionType == XMLRegionContext.XML_TAG_CLOSE) {
+ // change from empty tag may have impact on structure
+ if (!element.isEmptyTag())
+ continue;
+ } else if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME) {
+ // if new tag name is unchanged, it's OK
+ if (tagNameUnchanged)
+ continue;
+ }
+
+ // other region has changed
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+ }
+
+ // update attributes
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return; // error
+ NamedNodeMap attributes = element.getAttributes();
+ if (attributes == null)
+ return; // error
+
+ // first remove attributes
+ int regionIndex = 0;
+ int attrIndex = 0;
+ AttrImpl attr = null;
+ while (attrIndex < attributes.getLength()) {
+ attr = (AttrImpl) attributes.item(attrIndex);
+ if (attr == null) { // error
+ attrIndex++;
+ continue;
+ }
+ ITextRegion nameRegion = attr.getNameRegion();
+ if (nameRegion == null) { // error
+ element.removeAttributeNode(attr);
+ continue;
+ }
+ boolean found = false;
+ for (int i = regionIndex; i < regions.size(); i++) {
+ ITextRegion region = regions.get(i);
+ if (region == nameRegion) {
+ regionIndex = i + 1; // next region
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ attrIndex++;
+ } else {
+ element.removeAttributeNode(attr);
+ }
+ }
+
+ // insert or update attributes
+ attrIndex = 0; // reset to first
+ AttrImpl newAttr = null;
+ ITextRegion oldValueRegion = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) {
+ if (newAttr != null) {
+ // insert deferred new attribute
+ element.insertAttributeNode(newAttr, attrIndex++);
+ newAttr = null;
+ } else if (attr != null && oldValueRegion != null) {
+ // notify existing attribute value removal
+ attr.notifyValueChanged();
+ }
+
+ oldValueRegion = null;
+ attr = (AttrImpl) attributes.item(attrIndex);
+ if (attr != null && attr.getNameRegion() == region) {
+ // existing attribute
+ attrIndex++;
+ // clear other regions
+ oldValueRegion = attr.getValueRegion();
+ attr.setEqualRegion(null);
+ attr.setValueRegion(null);
+ } else {
+ String name = flatNode.getText(region);
+ attr = (AttrImpl) this.document.createAttribute(name);
+ if (attr != null)
+ attr.setNameRegion(region);
+ // defer insertion of new attribute
+ newAttr = attr;
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+ if (attr != null) {
+ attr.setEqualRegion(region);
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+ if (attr != null) {
+ attr.setValueRegion(region);
+ if (attr != newAttr && oldValueRegion != region) {
+ // notify existing attribute value changed
+ attr.notifyValueChanged();
+ }
+ oldValueRegion = null;
+ attr = null;
+ }
+ }
+ }
+
+ if (newAttr != null) {
+ // insert deferred new attribute
+ element.appendAttributeNode(newAttr);
+ } else if (attr != null && oldValueRegion != null) {
+ // notify existing attribute value removal
+ attr.notifyValueChanged();
+ }
+ }
+
+ /**
+ * changeStructuredDocumentRegion method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void changeStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ if (flatNode == null)
+ return;
+ if (this.document == null)
+ return;
+
+ setupContext(flatNode);
+
+ removeStructuredDocumentRegion(flatNode);
+ // make sure the parent is set to deepest level
+ // when end tag has been removed
+ this.context.setLast();
+ insertStructuredDocumentRegion(flatNode);
+
+ cleanupText();
+ cleanupEndTag();
+ }
+
+ /**
+ */
+ private void changeTagName(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ int offset = flatNode.getStart();
+ if (offset < 0)
+ return; // error
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return; // error
+ Node node = root.getNodeAt(offset);
+ if (node == null)
+ return; // error
+
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+
+ ElementImpl element = (ElementImpl) node;
+ String newTagName = flatNode.getText(region);
+ if (newTagName == null || !element.matchTagName(newTagName)) {
+ // the tag name is changed
+ changeStructuredDocumentRegion(flatNode);
+ return;
+ }
+
+ // the tag name is unchanged
+ // this happens when typing spaces after the tag name
+ // do nothing, but...
+ // if it's not a change in the end tag of an element with the start
+ // tag,
+ // and case has been changed, set to element and notify
+ if (!element.hasStartTag() || StructuredDocumentRegionUtil.getFirstRegionType(flatNode) != XMLRegionContext.XML_END_TAG_OPEN) {
+ String tagName = element.getTagName();
+ if (tagName == null || !tagName.equals(newTagName)) {
+ element.setTagName(newTagName);
+ element.notifyValueChanged();
+ }
+ }
+ }
+
+ /**
+ * cleanupContext method
+ */
+ private void cleanupEndTag() {
+ Node parent = this.context.getParentNode();
+ Node next = this.context.getNextNode();
+ while (parent != null) {
+ while (next != null) {
+ if (next.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) next;
+ if (element.isEndTag()) {
+ // floating end tag
+ String tagName = element.getTagName();
+ String rootName = getFindRootName(tagName);
+ ElementImpl start = (ElementImpl) this.context.findStartTag(tagName, rootName);
+ if (start != null) {
+ insertEndTag(start);
+ // move the end tag from 'element' to 'start'
+ start.addEndTag(element);
+ removeNode(element);
+ parent = this.context.getParentNode();
+ next = this.context.getNextNode();
+ continue;
+ }
+ }
+ }
+
+ Node first = next.getFirstChild();
+ if (first != null) {
+ parent = next;
+ next = first;
+ this.context.setNextNode(next);
+ } else {
+ next = next.getNextSibling();
+ this.context.setNextNode(next);
+ }
+ }
+
+ if (parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) parent;
+ if (!element.hasEndTag() && element.hasStartTag() && element.getNextSibling() == null) {
+ String tagName = element.getTagName();
+ ElementImpl end = (ElementImpl) this.context.findEndTag(tagName);
+ if (end != null) {
+ // move the end tag from 'end' to 'element'
+ element.addEndTag(end);
+ removeEndTag(end);
+ this.context.setParentNode(parent); // reset context
+ continue;
+ }
+ }
+ }
+
+ next = parent.getNextSibling();
+ parent = parent.getParentNode();
+ if (next != null) {
+ this.context.setNextNode(next);
+ } else {
+ this.context.setParentNode(parent);
+ }
+ }
+ }
+
+ /**
+ */
+ private void cleanupText() {
+ Node parent = this.context.getParentNode();
+ if (parent == null)
+ return; // error
+ Node next = this.context.getNextNode();
+ Node prev = (next == null ? parent.getLastChild() : next.getPreviousSibling());
+
+ TextImpl nextText = null;
+ TextImpl prevText = null;
+ if (next != null && next.getNodeType() == Node.TEXT_NODE) {
+ nextText = (TextImpl) next;
+ }
+ if (prev != null && prev.getNodeType() == Node.TEXT_NODE) {
+ prevText = (TextImpl) prev;
+ }
+ if (nextText == null && prevText == null)
+ return;
+ if (nextText != null && prevText != null) {
+ // consecutive Text nodes created by setupContext(),
+ // concat them
+ IStructuredDocumentRegion flatNode = nextText.getStructuredDocumentRegion();
+ if (flatNode != null)
+ prevText.appendStructuredDocumentRegion(flatNode);
+ Node newNext = next.getNextSibling();
+ parent.removeChild(next);
+ next = null;
+ this.context.setNextNode(newNext);
+ }
+
+ TextImpl childText = (prevText != null ? prevText : nextText);
+ if (childText.getNextSibling() == null && childText.getPreviousSibling() == null) {
+ if (parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl parentElement = (ElementImpl) parent;
+ if (!parentElement.hasStartTag() && !parentElement.hasEndTag()) {
+ if (childText.isWhitespace() || childText.isInvalid()) {
+ // implicit parent is not required
+ Node newParent = parent.getParentNode();
+ if (newParent != null) {
+ Node newNext = parent.getNextSibling();
+ newParent.removeChild(parent);
+ parent.removeChild(childText);
+ newParent.insertBefore(childText, newNext);
+ if (childText == next) {
+ this.context.setNextNode(childText);
+ } else if (newNext != null) {
+ this.context.setNextNode(newNext);
+ } else {
+ this.context.setParentNode(newParent);
+ }
+ // try again
+ cleanupText();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This routine create an Element from comment data for comment style
+ * elements, such as SSI and METADATA
+ */
+ protected Element createCommentElement(String data, boolean isJSPTag) {
+ String trimmedData = data.trim();
+ CommentElementConfiguration[] configs = CommentElementRegistry.getInstance().getConfigurations();
+ for (int iConfig = 0; iConfig < configs.length; iConfig++) {
+ CommentElementConfiguration config = configs[iConfig];
+ if ((isJSPTag && !config.acceptJSPComment()) || (!isJSPTag && !config.acceptXMLComment())) {
+ continue;
+ }
+ String[] prefixes = config.getPrefix();
+ for (int iPrefix = 0; iPrefix < prefixes.length; iPrefix++) {
+ if (trimmedData.startsWith(prefixes[iPrefix])) {
+ return config.createElement(this.document, data, isJSPTag);
+ }
+ }
+ }
+ if (this.adapter != null) {
+ return this.adapter.createCommentElement(this.document, data, isJSPTag);
+ }
+ return null;
+ }
+
+ /**
+ * This routine create an implicit Element for given parent and child,
+ * such as HTML, BODY, HEAD, and TBODY for HTML document.
+ */
+ protected Element createImplicitElement(Node parent, Node child) {
+ if (this.adapter != null) {
+ return this.adapter.createImplicitElement(this.document, parent, child);
+ }
+ return null;
+ }
+
+ /**
+ */
+ private void demoteNodes(Node root, Node newParent, Node oldParent, Node next) {
+ if (newParent.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ ElementImpl newElement = (ElementImpl) newParent;
+
+ // find next
+ while (next == null) {
+ if (oldParent.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ ElementImpl oldElement = (ElementImpl) oldParent;
+ if (oldElement.hasEndTag())
+ return;
+ oldParent = oldElement.getParentNode();
+ if (oldParent == null)
+ return; // error
+ next = oldElement.getNextSibling();
+ }
+
+ while (next != null) {
+ boolean done = false;
+ if (next.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl nextElement = (ElementImpl) next;
+ if (!nextElement.hasStartTag()) {
+ Node nextChild = nextElement.getFirstChild();
+ if (nextChild != null) {
+ // demote children
+ next = nextChild;
+ oldParent = nextElement;
+ continue;
+ }
+
+ if (nextElement.hasEndTag()) {
+ if (nextElement.matchEndTag(newElement)) {
+ // stop at the matched invalid end tag
+ next = nextElement.getNextSibling();
+ oldParent.removeChild(nextElement);
+ newElement.addEndTag(nextElement);
+
+ if (newElement == root)
+ return;
+ Node p = newElement.getParentNode();
+ // check if reached to top
+ if (p == null || p == oldParent || p.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ newElement = (ElementImpl) p;
+ done = true;
+ }
+ } else {
+ // remove implicit element
+ next = nextElement.getNextSibling();
+ oldParent.removeChild(nextElement);
+ done = true;
+ }
+ }
+ }
+
+ if (!done) {
+ if (!canContain(newElement, next)) {
+ if (newElement == root)
+ return;
+ Node p = newElement.getParentNode();
+ // check if reached to top
+ if (p == null || p == oldParent || p.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ newElement = (ElementImpl) p;
+ continue;
+ }
+
+ Node child = next;
+ next = next.getNextSibling();
+ oldParent.removeChild(child);
+ insertNode(newElement, child, null);
+ Node childParent = child.getParentNode();
+ if (childParent != newElement) {
+ newElement = (ElementImpl) childParent;
+ }
+ }
+
+ // find next parent and sibling
+ while (next == null) {
+ if (oldParent.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ ElementImpl oldElement = (ElementImpl) oldParent;
+
+ // dug parent must not have children at this point
+ if (!oldElement.hasChildNodes() && !oldElement.hasStartTag()) {
+ oldParent = oldElement.getParentNode();
+ if (oldParent == null)
+ return; // error
+ next = oldElement;
+ break;
+ }
+
+ if (oldElement.hasEndTag())
+ return;
+ oldParent = oldElement.getParentNode();
+ if (oldParent == null)
+ return; // error
+ next = oldElement.getNextSibling();
+ }
+ }
+ }
+
+ /**
+ */
+ protected final XMLDocument getDocument() {
+ return this.document;
+ }
+
+ /**
+ */
+ protected String getFindRootName(String tagName) {
+ if (this.adapter != null) {
+ return this.adapter.getFindRootName(tagName);
+ }
+ return null;
+ }
+
+ /**
+ */
+ protected final XMLModel getModel() {
+ return this.model;
+ }
+
+ /**
+ * insertCDATASection method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertCDATASection(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ CDATASectionImpl cdata = null;
+ try {
+ cdata = (CDATASectionImpl) this.document.createCDATASection(null);
+ } catch (DOMException ex) {
+ }
+ if (cdata == null) { // CDATA section might not be supported
+ insertInvalidDecl(flatNode); // regard as invalid decl
+ return;
+ }
+
+ cdata.setStructuredDocumentRegion(flatNode);
+ insertNode(cdata);
+ }
+
+ /**
+ * insertComment method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertComment(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ String data = null;
+ boolean isJSPTag = false;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == JSP_COMMENT_OPEN) {
+ isJSPTag = true;
+ } else if (regionType == XMLRegionContext.XML_COMMENT_TEXT || regionType == JSP_COMMENT_TEXT) {
+ if (data == null) {
+ data = flatNode.getText(region);
+ }
+ }
+ }
+
+ if (data != null) {
+ ElementImpl element = (ElementImpl) createCommentElement(data, isJSPTag);
+ if (element != null) {
+ if (!isEndTag(element)) {
+ element.setStartStructuredDocumentRegion(flatNode);
+ insertStartTag(element);
+ return;
+ }
+
+ // end tag
+ element.setEndStructuredDocumentRegion(flatNode);
+
+ String tagName = element.getTagName();
+ String rootName = getFindRootName(tagName);
+ ElementImpl start = (ElementImpl) this.context.findStartTag(tagName, rootName);
+ if (start != null) { // start tag found
+ insertEndTag(start);
+ start.addEndTag(element);
+ return;
+ }
+
+ // invalid end tag
+ insertNode(element);
+ return;
+ }
+ }
+
+ CommentImpl comment = (CommentImpl) this.document.createComment(null);
+ if (comment == null)
+ return;
+ if (isJSPTag)
+ comment.setJSPTag(true);
+ comment.setStructuredDocumentRegion(flatNode);
+ insertNode(comment);
+ }
+
+ /**
+ * insertDecl method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertDecl(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ boolean isDocType = false;
+ String name = null;
+ String publicId = null;
+ String systemId = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_DOCTYPE_DECLARATION) {
+ isDocType = true;
+ } else if (regionType == XMLRegionContext.XML_DOCTYPE_NAME) {
+ if (name == null)
+ name = flatNode.getText(region);
+ } else if (regionType == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_PUBREF) {
+ if (publicId == null)
+ publicId = StructuredDocumentRegionUtil.getAttrValue(flatNode, region);
+ } else if (regionType == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_SYSREF) {
+ if (systemId == null)
+ systemId = StructuredDocumentRegionUtil.getAttrValue(flatNode, region);
+ }
+ }
+
+ // invalid declaration
+ if (!isDocType) {
+ insertInvalidDecl(flatNode);
+ return;
+ }
+
+ DocumentTypeImpl docType = (DocumentTypeImpl) this.document.createDoctype(name);
+ if (docType == null)
+ return;
+ if (publicId != null)
+ docType.setPublicId(publicId);
+ if (systemId != null)
+ docType.setSystemId(systemId);
+ docType.setStructuredDocumentRegion(flatNode);
+ insertNode(docType);
+ }
+
+ /**
+ * insertEndTag method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ */
+ private void insertEndTag(Element element) {
+ if (element == null)
+ return;
+
+ Node newParent = element.getParentNode();
+ if (newParent == null)
+ return; // error
+
+ if (!((ElementImpl) element).isContainer()) {
+ // just update context
+ Node elementNext = element.getNextSibling();
+ if (elementNext != null)
+ this.context.setNextNode(elementNext);
+ else
+ this.context.setParentNode(newParent);
+ return;
+ }
+
+ // promote children
+ Node newNext = element.getNextSibling();
+ Node oldParent = this.context.getParentNode();
+ if (oldParent == null)
+ return; // error
+ Node oldNext = this.context.getNextNode();
+ promoteNodes(element, newParent, newNext, oldParent, oldNext);
+
+ // update context
+ // re-check the next sibling
+ newNext = element.getNextSibling();
+ if (newNext != null)
+ this.context.setNextNode(newNext);
+ else
+ this.context.setParentNode(newParent);
+ }
+
+ /**
+ * insertEndTag method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertEndTag(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ String tagName = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ if (region.getType() == XMLRegionContext.XML_TAG_NAME || region.getType() == JSP_ROOT_TAG_NAME || region.getType() == JSP_DIRECTIVE_NAME) {
+ if (tagName == null)
+ tagName = flatNode.getText(region);
+ }
+ }
+
+ if (tagName == null) { // invalid end tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+
+ String rootName = getFindRootName(tagName);
+ ElementImpl start = (ElementImpl) this.context.findStartTag(tagName, rootName);
+ if (start != null) { // start tag found
+ insertEndTag(start);
+ start.setEndStructuredDocumentRegion(flatNode);
+ return;
+ }
+
+ // invalid end tag
+ ElementImpl end = null;
+ try {
+ end = (ElementImpl) this.document.createElement(tagName);
+ } catch (DOMException ex) {
+ }
+ if (end == null) { // invalid end tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+ end.setEndStructuredDocumentRegion(flatNode);
+ insertNode(end);
+ }
+
+ /**
+ * insertEntityRef method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertEntityRef(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ String name = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_CHAR_REFERENCE) {
+ if (name == null)
+ name = StructuredDocumentRegionUtil.getEntityRefName(flatNode, region);
+ }
+ }
+
+ if (name == null) { // invalid entity
+ insertText(flatNode);
+ return;
+ }
+
+ String value = this.document.getCharValue(name);
+ if (value != null) { // character entity
+ TextImpl text = (TextImpl) this.context.findPreviousText();
+ if (text != null) { // existing text found
+ // do not append data
+ text.appendStructuredDocumentRegion(flatNode);
+ // notify the change
+ text.notifyValueChanged();
+ return;
+ }
+
+ // new text
+ text = (TextImpl) this.document.createTextNode(null);
+ if (text == null)
+ return;
+ text.setStructuredDocumentRegion(flatNode);
+ insertNode(text);
+ return;
+ }
+
+ // general entity reference
+ EntityReferenceImpl ref = null;
+ try {
+ ref = (EntityReferenceImpl) this.document.createEntityReference(name);
+ } catch (DOMException ex) {
+ }
+ if (ref == null) { // entity reference might not be supported
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+
+ ref.setStructuredDocumentRegion(flatNode);
+ insertNode(ref);
+ }
+
+ /**
+ * insertInvalidDecl method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertInvalidDecl(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ ElementImpl element = null;
+ try {
+ element = (ElementImpl) this.document.createElement("!");//$NON-NLS-1$
+ } catch (DOMException ex) {
+ }
+ if (element == null) { // invalid tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+ element.setEmptyTag(true);
+ element.setStartStructuredDocumentRegion(flatNode);
+ insertNode(element);
+ }
+
+ /**
+ * insertJSPTag method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertJSPTag(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ String tagName = null;
+ AttrImpl attr = null;
+ Vector attrNodes = null;
+ boolean isCloseTag = false;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == JSP_SCRIPTLET_OPEN) {
+ tagName = JSPTag.JSP_SCRIPTLET;
+ } else if (regionType == JSP_EXPRESSION_OPEN) {
+ tagName = JSPTag.JSP_EXPRESSION;
+ } else if (regionType == JSP_DECLARATION_OPEN) {
+ tagName = JSPTag.JSP_DECLARATION;
+ } else if (regionType == JSP_DIRECTIVE_OPEN) {
+ tagName = JSPTag.JSP_DIRECTIVE;
+ } else if (regionType == JSP_DIRECTIVE_NAME) {
+ tagName += '.';
+ tagName += flatNode.getText(region);
+ } else if (regionType == JSP_CLOSE) {
+ isCloseTag = true;
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) {
+ String name = flatNode.getText(region);
+ attr = (AttrImpl) this.document.createAttribute(name);
+ if (attr != null) {
+ attr.setNameRegion(region);
+ if (attrNodes == null)
+ attrNodes = new Vector();
+ attrNodes.addElement(attr);
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+ if (attr != null) {
+ attr.setEqualRegion(region);
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+ if (attr != null) {
+ attr.setValueRegion(region);
+ attr = null;
+ }
+ }
+ }
+
+ if (tagName == null) {
+ if (isCloseTag) {
+ // close JSP tag
+ Node parent = this.context.getParentNode();
+ if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl start = (ElementImpl) parent;
+ if (start.isJSPContainer()) {
+ insertEndTag(start);
+ start.setEndStructuredDocumentRegion(flatNode);
+ return;
+ }
+ }
+ }
+ // invalid JSP tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+
+ ElementImpl element = null;
+ try {
+ element = (ElementImpl) this.document.createElement(tagName);
+ } catch (DOMException ex) {
+ }
+ if (element == null) { // invalid tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+ if (attrNodes != null) {
+ Enumeration ae = attrNodes.elements();
+ while (ae.hasMoreElements()) {
+ Attr a = (Attr) ae.nextElement();
+ if (a == null)
+ continue;
+ element.appendAttributeNode(a);
+ }
+ }
+ element.setJSPTag(true);
+ element.setStartStructuredDocumentRegion(flatNode);
+ insertStartTag(element);
+ }
+
+ /**
+ * insertNode method
+ *
+ * @param child
+ * org.w3c.dom.Node
+ */
+ private void insertNode(Node node) {
+ if (node == null)
+ return;
+ if (this.context == null)
+ return;
+
+ Node parent = this.context.getParentNode();
+ if (parent == null)
+ return;
+ Node next = this.context.getNextNode();
+ while (parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) parent;
+ if (canContain(element, node)) {
+ if (!element.hasStartTag() && next == element.getFirstChild()) {
+ // first child of implicit tag
+ // deletege to the parent
+ parent = element.getParentNode();
+ if (parent == null)
+ return;
+ next = element;
+ this.context.setNextNode(next);
+ continue;
+ }
+ break;
+ }
+ parent = element.getParentNode();
+ if (parent == null)
+ return;
+
+ // promote siblings
+ Node newNext = element.getNextSibling();
+ Node child = next;
+ while (child != null) {
+ Node nextChild = child.getNextSibling();
+ element.removeChild(child);
+ parent.insertBefore(child, newNext);
+ child = nextChild;
+ }
+
+ // leave the old end tag where it is
+ if (element.hasEndTag()) {
+ Element end = element.removeEndTag();
+ if (end != null) {
+ parent.insertBefore(end, newNext);
+ if (next == null)
+ next = end;
+ }
+ }
+ if (!element.hasStartTag()) {
+ // implicit element
+ if (!element.hasChildNodes()) {
+ parent.removeChild(element);
+ }
+ }
+
+ // update context
+ if (next == null)
+ next = newNext;
+ if (next != null)
+ this.context.setNextNode(next);
+ else
+ this.context.setParentNode(parent);
+ }
+
+ insertNode(parent, node, next);
+ next = node.getNextSibling();
+ if (next != null)
+ this.context.setNextNode(next);
+ else
+ this.context.setParentNode(node.getParentNode());
+ }
+
+ /**
+ */
+ private void insertNode(Node parent, Node node, Node next) {
+ while (next != null && next.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl nextElement = (ElementImpl) next;
+ if (nextElement.hasStartTag())
+ break;
+ if (!canBeImplicitTag(nextElement, node))
+ break;
+ parent = nextElement;
+ next = nextElement.getFirstChild();
+ }
+ Element implicitElement = createImplicitElement(parent, node);
+ if (implicitElement != null)
+ node = implicitElement;
+ parent.insertBefore(node, next);
+ }
+
+ /**
+ * insertPI method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertPI(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ String target = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_PI_OPEN || regionType == XMLRegionContext.XML_PI_CLOSE)
+ continue;
+ if (target == null)
+ target = flatNode.getText(region);
+ }
+
+ ProcessingInstructionImpl pi = (ProcessingInstructionImpl) this.document.createProcessingInstruction(target, null);
+ if (pi == null)
+ return;
+ pi.setStructuredDocumentRegion(flatNode);
+ insertNode(pi);
+ }
+
+ /**
+ * insertStartTag method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ */
+ private void insertStartTag(Element element) {
+ if (element == null)
+ return;
+ if (this.context == null)
+ return;
+
+ insertNode(element);
+
+ ElementImpl newElement = (ElementImpl) element;
+ if (newElement.isEmptyTag() || !newElement.isContainer())
+ return;
+
+ // demote siblings
+ Node parent = this.context.getParentNode();
+ if (parent == null)
+ return; // error
+ Node next = this.context.getNextNode();
+ demoteNodes(element, element, parent, next);
+
+ // update context
+ Node firstChild = element.getFirstChild();
+ if (firstChild != null)
+ this.context.setNextNode(firstChild);
+ else
+ this.context.setParentNode(element);
+ }
+
+ /**
+ * insertStartTag method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertStartTag(IStructuredDocumentRegion flatNode) {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+
+ String tagName = null;
+ boolean isEmptyTag = false;
+ AttrImpl attr = null;
+ Vector attrNodes = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME || regionType == JSP_DIRECTIVE_NAME) {
+ if (tagName == null)
+ tagName = flatNode.getText(region);
+ } else if (regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE) {
+ isEmptyTag = true;
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) {
+ String name = flatNode.getText(region);
+ attr = (AttrImpl) this.document.createAttribute(name);
+ if (attr != null) {
+ attr.setNameRegion(region);
+ if (attrNodes == null)
+ attrNodes = new Vector();
+ attrNodes.addElement(attr);
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+ if (attr != null) {
+ attr.setEqualRegion(region);
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+ if (attr != null) {
+ attr.setValueRegion(region);
+ attr = null;
+ }
+ }
+ }
+
+ if (tagName == null) { // invalid start tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+
+ ElementImpl element = null;
+ try {
+ element = (ElementImpl) this.document.createElement(tagName);
+ } catch (DOMException ex) {
+ }
+ if (element == null) { // invalid tag
+ insertText(flatNode); // regard as invalid text
+ return;
+ }
+ if (attrNodes != null) {
+ Enumeration ae = attrNodes.elements();
+ while (ae.hasMoreElements()) {
+ Attr a = (Attr) ae.nextElement();
+ if (a == null)
+ continue;
+ element.appendAttributeNode(a);
+ }
+ }
+ if (isEmptyTag)
+ element.setEmptyTag(true);
+ element.setStartStructuredDocumentRegion(flatNode);
+ insertStartTag(element);
+ }
+
+ /**
+ * insertStructuredDocumentRegion method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertStructuredDocumentRegion(IStructuredDocumentRegion flatNode) {
+ String regionType = StructuredDocumentRegionUtil.getFirstRegionType(flatNode);
+ if (regionType == XMLRegionContext.XML_TAG_OPEN) {
+ insertStartTag(flatNode);
+ } else if (regionType == XMLRegionContext.XML_END_TAG_OPEN) {
+ insertEndTag(flatNode);
+ } else if (regionType == XMLRegionContext.XML_COMMENT_OPEN || regionType == JSP_COMMENT_OPEN) {
+ insertComment(flatNode);
+ } else if (regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_CHAR_REFERENCE) {
+ insertEntityRef(flatNode);
+ } else if (regionType == XMLRegionContext.XML_DECLARATION_OPEN) {
+ insertDecl(flatNode);
+ } else if (regionType == XMLRegionContext.XML_PI_OPEN) {
+ insertPI(flatNode);
+ } else if (regionType == XMLRegionContext.XML_CDATA_OPEN) {
+ insertCDATASection(flatNode);
+ } else if (regionType == JSP_SCRIPTLET_OPEN || regionType == JSP_EXPRESSION_OPEN || regionType == JSP_DECLARATION_OPEN || regionType == JSP_DIRECTIVE_OPEN || regionType == JSP_CLOSE) {
+ insertJSPTag(flatNode);
+ } else {
+ insertText(flatNode);
+ }
+ }
+
+ /**
+ * insertText method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void insertText(IStructuredDocumentRegion flatNode) {
+ TextImpl text = (TextImpl) this.context.findPreviousText();
+ if (text != null) { // existing text found
+ text.appendStructuredDocumentRegion(flatNode);
+ // notify the change
+ text.notifyValueChanged();
+ return;
+ }
+
+ // new text
+ text = (TextImpl) this.document.createTextNode(null);
+ if (text == null)
+ return;
+ text.setStructuredDocumentRegion(flatNode);
+ insertNode(text);
+ }
+
+ /**
+ */
+ protected boolean isEndTag(XMLElement element) {
+ if (this.adapter != null) {
+ return this.adapter.isEndTag(element);
+ }
+ return element.isEndTag();
+ }
+
+ /**
+ */
+ private void promoteNodes(Node root, Node newParent, Node newNext, Node oldParent, Node next) {
+ ElementImpl newElement = null;
+ if (newParent.getNodeType() == Node.ELEMENT_NODE) {
+ newElement = (ElementImpl) newParent;
+ }
+
+ Node rootParent = root.getParentNode();
+ while (oldParent != rootParent) {
+ while (next != null) {
+ boolean done = false;
+ boolean endTag = false;
+ if (next.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl nextElement = (ElementImpl) next;
+ if (!nextElement.hasStartTag()) {
+ Node nextChild = nextElement.getFirstChild();
+ if (nextChild != null) {
+ // promote children
+ next = nextChild;
+ oldParent = nextElement;
+ continue;
+ }
+
+ if (nextElement.hasEndTag()) {
+ if (nextElement.matchEndTag(newElement)) {
+ endTag = true;
+ }
+ } else {
+ // remove implicit element
+ next = nextElement.getNextSibling();
+ oldParent.removeChild(nextElement);
+ done = true;
+ }
+ }
+ }
+
+ if (!done) {
+ if (!endTag && newElement != null && !canContain(newElement, next)) {
+ newParent = newElement.getParentNode();
+ if (newParent == null)
+ return; // error
+ Node elementNext = newElement.getNextSibling();
+ // promote siblings
+ promoteNodes(newElement, newParent, elementNext, newElement, newNext);
+ newNext = newElement.getNextSibling();
+ if (newParent.getNodeType() == Node.ELEMENT_NODE) {
+ newElement = (ElementImpl) newParent;
+ } else {
+ newElement = null;
+ }
+ continue;
+ }
+
+ Node child = next;
+ next = next.getNextSibling();
+ oldParent.removeChild(child);
+ insertNode(newParent, child, newNext);
+ Node childParent = child.getParentNode();
+ if (childParent != newParent) {
+ newParent = childParent;
+ newElement = (ElementImpl) newParent;
+ newNext = child.getNextSibling();
+ }
+ }
+ }
+
+ if (oldParent.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ ElementImpl oldElement = (ElementImpl) oldParent;
+ oldParent = oldElement.getParentNode();
+ if (oldParent == null)
+ return; // error
+ next = oldElement.getNextSibling();
+
+ if (oldElement.hasEndTag()) {
+ Element end = null;
+ if (!oldElement.hasChildNodes() && !oldElement.hasStartTag()) {
+ oldParent.removeChild(oldElement);
+ end = oldElement;
+ } else {
+ end = oldElement.removeEndTag();
+ }
+ if (end != null) {
+ insertNode(newParent, end, newNext);
+ Node endParent = end.getParentNode();
+ if (endParent != newParent) {
+ newParent = endParent;
+ newElement = (ElementImpl) newParent;
+ newNext = end.getNextSibling();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * removeEndTag method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ */
+ private void removeEndTag(Element element) {
+ if (element == null)
+ return;
+ if (this.context == null)
+ return;
+
+ Node parent = element.getParentNode();
+ if (parent == null)
+ return; // error
+
+ if (!((ElementImpl) element).isContainer()) {
+ // just update context
+ Node elementNext = element.getNextSibling();
+ if (elementNext != null)
+ this.context.setNextNode(elementNext);
+ else
+ this.context.setParentNode(parent);
+ return;
+ }
+
+ // demote siblings
+ Node next = element.getNextSibling();
+ ElementImpl newElement = (ElementImpl) element;
+ // find new parent
+ for (Node last = newElement.getLastChild(); last != null; last = last.getLastChild()) {
+ if (last.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl lastElement = (ElementImpl) last;
+ if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer())
+ break;
+ newElement = lastElement;
+ }
+ Node lastChild = newElement.getLastChild();
+ demoteNodes(element, newElement, parent, next);
+
+ // update context
+ Node newNext = null;
+ if (lastChild != null)
+ newNext = lastChild.getNextSibling();
+ else
+ newNext = newElement.getFirstChild();
+ if (newNext != null)
+ this.context.setNextNode(newNext);
+ else
+ this.context.setParentNode(newElement);
+ }
+
+ /**
+ * Remove the specified node if it is no longer required implicit tag with
+ * remaining child nodes promoted.
+ */
+ private Element removeImplicitElement(Node parent) {
+ if (parent == null)
+ return null;
+ if (parent.getNodeType() != Node.ELEMENT_NODE)
+ return null;
+ ElementImpl element = (ElementImpl) parent;
+ if (!element.isImplicitTag())
+ return null;
+ if (canBeImplicitTag(element))
+ return null;
+
+ Node elementParent = element.getParentNode();
+ if (elementParent == null)
+ return null; // error
+ Node firstChild = element.getFirstChild();
+ Node child = firstChild;
+ Node elementNext = element.getNextSibling();
+ while (child != null) {
+ Node nextChild = child.getNextSibling();
+ element.removeChild(child);
+ elementParent.insertBefore(child, elementNext);
+ child = nextChild;
+ }
+
+ // reset context
+ if (this.context.getParentNode() == element) {
+ Node oldNext = this.context.getNextNode();
+ if (oldNext != null) {
+ this.context.setNextNode(oldNext);
+ } else {
+ if (elementNext != null) {
+ this.context.setNextNode(elementNext);
+ } else {
+ this.context.setParentNode(elementParent);
+ }
+ }
+ } else if (this.context.getNextNode() == element) {
+ if (firstChild != null) {
+ this.context.setNextNode(firstChild);
+ } else {
+ if (elementNext != null) {
+ this.context.setNextNode(elementNext);
+ } else {
+ this.context.setParentNode(elementParent);
+ }
+ }
+ }
+
+ removeNode(element);
+ return element;
+ }
+
+ /**
+ * removeNode method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ private void removeNode(Node node) {
+ if (node == null)
+ return;
+ if (this.context == null)
+ return;
+
+ Node parent = node.getParentNode();
+ if (parent == null)
+ return;
+ Node next = node.getNextSibling();
+ Node prev = node.getPreviousSibling();
+
+ // update context
+ Node oldParent = this.context.getParentNode();
+ if (node == oldParent) {
+ if (next != null)
+ this.context.setNextNode(next);
+ else
+ this.context.setParentNode(parent);
+ } else {
+ Node oldNext = this.context.getNextNode();
+ if (node == oldNext) {
+ this.context.setNextNode(next);
+ }
+ }
+
+ parent.removeChild(node);
+
+ if (removeImplicitElement(parent) != null)
+ return;
+
+ // demote sibling
+ if (prev != null && prev.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl newElement = (ElementImpl) prev;
+ if (!newElement.hasEndTag() && !newElement.isEmptyTag() && newElement.isContainer()) {
+ // find new parent
+ for (Node last = newElement.getLastChild(); last != null; last = last.getLastChild()) {
+ if (last.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl lastElement = (ElementImpl) last;
+ if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer())
+ break;
+ newElement = lastElement;
+ }
+ Node lastChild = newElement.getLastChild();
+ demoteNodes(prev, newElement, parent, next);
+
+ // update context
+ Node newNext = null;
+ if (lastChild != null)
+ newNext = lastChild.getNextSibling();
+ else
+ newNext = newElement.getFirstChild();
+ if (newNext != null)
+ this.context.setNextNode(newNext);
+ else
+ this.context.setParentNode(newElement);
+ }
+ }
+ }
+
+ /**
+ * removeStartTag method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ */
+ private void removeStartTag(Element element) {
+ if (element == null)
+ return;
+ if (this.context == null)
+ return;
+
+ // for implicit tag
+ ElementImpl oldElement = (ElementImpl) element;
+ if (canBeImplicitTag(oldElement)) {
+ Node newParent = null;
+ Node prev = oldElement.getPreviousSibling();
+ if (prev != null && prev.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl prevElement = (ElementImpl) prev;
+ if (!prevElement.hasEndTag()) {
+ if (prevElement.hasStartTag() || prevElement.matchTagName(oldElement.getTagName())) {
+ newParent = prevElement;
+ }
+ }
+ }
+ if (newParent == null) {
+ // this element should stay as implicit tag
+ // just remove all attributes
+ oldElement.removeStartTag();
+
+ // update context
+ Node child = oldElement.getFirstChild();
+ if (child != null) {
+ this.context.setNextNode(child);
+ } else if (oldElement.hasEndTag()) {
+ this.context.setParentNode(oldElement);
+ }
+ return;
+ }
+ }
+ // for comment tag
+ if (oldElement.isCommentTag())
+ oldElement.removeStartTag();
+
+ // promote children
+ Node elementParent = element.getParentNode();
+ Node parent = elementParent;
+ if (parent == null)
+ return;
+ Node first = element.getFirstChild();
+ Node firstElement = null; // for the case first is removed as end tag
+ if (first != null) {
+ // find new parent for children
+ ElementImpl newElement = null;
+ for (Node last = element.getPreviousSibling(); last != null; last = last.getLastChild()) {
+ if (last.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl lastElement = (ElementImpl) last;
+ if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer())
+ break;
+ newElement = lastElement;
+ }
+ Node next = first;
+ if (newElement != null) {
+ while (next != null) {
+ if (!newElement.hasEndTag() && newElement.hasStartTag() && next.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl nextElement = (ElementImpl) next;
+ if (!nextElement.hasStartTag() && nextElement.hasEndTag() && nextElement.matchEndTag(newElement)) {
+ // stop at the matched invalid end tag
+ Node elementChild = nextElement.getFirstChild();
+ while (elementChild != null) {
+ Node nextChild = elementChild.getNextSibling();
+ nextElement.removeChild(elementChild);
+ newElement.appendChild(elementChild);
+ elementChild = nextChild;
+ }
+
+ next = nextElement.getNextSibling();
+ element.removeChild(nextElement);
+ newElement.addEndTag(nextElement);
+ if (nextElement == first)
+ firstElement = newElement;
+
+ Node newParent = newElement.getParentNode();
+ if (newParent == parent)
+ break;
+ if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE)
+ break; // error
+ newElement = (ElementImpl) newParent;
+ continue;
+ }
+ }
+ if (!canContain(newElement, next)) {
+ Node newParent = newElement.getParentNode();
+ if (newParent == parent)
+ break;
+ if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE)
+ break; // error
+ newElement = (ElementImpl) newParent;
+ continue;
+ }
+ Node child = next;
+ next = next.getNextSibling();
+ element.removeChild(child);
+ newElement.appendChild(child);
+ }
+ newElement = null;
+ }
+ if (parent.getNodeType() == Node.ELEMENT_NODE) {
+ newElement = (ElementImpl) parent;
+ }
+ while (next != null) {
+ if (newElement == null || canContain(newElement, next)) {
+ Node child = next;
+ next = next.getNextSibling();
+ element.removeChild(child);
+ parent.insertBefore(child, element);
+ continue;
+ }
+
+ parent = newElement.getParentNode();
+ if (parent == null)
+ return;
+
+ // promote siblings
+ Node newNext = newElement.getNextSibling();
+ Node child = element;
+ while (child != null) {
+ Node nextChild = child.getNextSibling();
+ newElement.removeChild(child);
+ parent.insertBefore(child, newNext);
+ child = nextChild;
+ }
+
+ // leave the old end tag where it is
+ if (newElement.hasEndTag()) {
+ Element end = newElement.removeEndTag();
+ if (end != null) {
+ parent.insertBefore(end, newNext);
+ }
+ }
+ if (!newElement.hasStartTag()) {
+ // implicit element
+ if (!newElement.hasChildNodes()) {
+ parent.removeChild(newElement);
+ }
+ }
+
+ if (parent.getNodeType() == Node.ELEMENT_NODE) {
+ newElement = (ElementImpl) parent;
+ } else {
+ newElement = null;
+ }
+ }
+ }
+
+ Node newNext = element;
+ Node startElement = null; // for the case element is removed as end
+ // tag
+ if (oldElement.hasEndTag()) {
+ // find new parent for invalid end tag and siblings
+ ElementImpl newElement = null;
+ for (Node last = element.getPreviousSibling(); last != null; last = last.getLastChild()) {
+ if (last.getNodeType() != Node.ELEMENT_NODE)
+ break;
+ ElementImpl lastElement = (ElementImpl) last;
+ if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer())
+ break;
+ newElement = lastElement;
+ }
+ if (newElement != null) {
+ // demote invalid end tag and sibling
+ Node next = element;
+ while (next != null) {
+ if (!newElement.hasEndTag() && newElement.hasStartTag() && next.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl nextElement = (ElementImpl) next;
+ if (!nextElement.hasStartTag() && nextElement.hasEndTag() && nextElement.matchEndTag(newElement)) {
+ // stop at the matched invalid end tag
+ Node elementChild = nextElement.getFirstChild();
+ while (elementChild != null) {
+ Node nextChild = elementChild.getNextSibling();
+ nextElement.removeChild(elementChild);
+ newElement.appendChild(elementChild);
+ elementChild = nextChild;
+ }
+
+ next = nextElement.getNextSibling();
+ parent.removeChild(nextElement);
+ newElement.addEndTag(nextElement);
+ if (nextElement == newNext)
+ startElement = newElement;
+
+ Node newParent = newElement.getParentNode();
+ if (newParent == parent)
+ break;
+ if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE)
+ break; // error
+ newElement = (ElementImpl) newParent;
+ continue;
+ }
+ }
+ if (!canContain(newElement, next)) {
+ Node newParent = newElement.getParentNode();
+ if (newParent == parent)
+ break;
+ if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE)
+ break; // error
+ newElement = (ElementImpl) newParent;
+ continue;
+ }
+ Node child = next;
+ next = next.getNextSibling();
+ parent.removeChild(child);
+ if (child == oldElement) {
+ if (!oldElement.isCommentTag()) {
+ // clone (re-create) end tag
+ Element end = oldElement.removeEndTag();
+ if (end != null) {
+ child = end;
+ newNext = end;
+ }
+ }
+ }
+ newElement.appendChild(child);
+ }
+ } else {
+ if (!oldElement.isCommentTag()) {
+ // clone (re-create) end tag
+ Element end = oldElement.removeEndTag();
+ if (end != null) {
+ parent.insertBefore(end, oldElement);
+ parent.removeChild(oldElement);
+ newNext = end;
+ }
+ }
+ }
+ } else {
+ newNext = oldElement.getNextSibling();
+ parent.removeChild(oldElement);
+ }
+
+ // update context
+ Node oldParent = this.context.getParentNode();
+ Node oldNext = this.context.getNextNode();
+ if (element == oldParent) {
+ if (oldNext != null) {
+ this.context.setNextNode(oldNext); // reset for new parent
+ } else if (newNext != null) {
+ this.context.setNextNode(newNext);
+ } else {
+ this.context.setParentNode(parent);
+ }
+ } else if (element == oldNext) {
+ if (firstElement != null) {
+ this.context.setParentNode(firstElement);
+ } else if (first != null) {
+ this.context.setNextNode(first);
+ } else if (startElement != null) {
+ this.context.setParentNode(startElement);
+ } else {
+ this.context.setNextNode(newNext);
+ }
+ }
+
+ removeImplicitElement(elementParent);
+ }
+
+ /**
+ * removeStructuredDocumentRegion method
+ *
+ * @param oldStructuredDocumentRegion
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ NodeImpl next = (NodeImpl) this.context.getNextNode();
+ if (next != null) {
+ short nodeType = next.getNodeType();
+ if (nodeType != Node.ELEMENT_NODE) {
+ IStructuredDocumentRegion flatNode = next.getStructuredDocumentRegion();
+ if (flatNode == oldStructuredDocumentRegion) {
+ removeNode(next);
+ return;
+ }
+ if (nodeType != Node.TEXT_NODE) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ if (flatNode == null) {
+ // this is the case for empty Text
+ // remove and continue
+ removeNode(next);
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+ TextImpl text = (TextImpl) next;
+ boolean isShared = text.isSharingStructuredDocumentRegion(oldStructuredDocumentRegion);
+ if (isShared) {
+ // make sure there is next Text node sharing this
+ TextImpl nextText = (TextImpl) this.context.findNextText();
+ if (nextText == null || !nextText.hasStructuredDocumentRegion(oldStructuredDocumentRegion)) {
+ isShared = false;
+ }
+ }
+ oldStructuredDocumentRegion = text.removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ if (oldStructuredDocumentRegion == null) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ if (text.getStructuredDocumentRegion() == null) {
+ // this is the case partial IStructuredDocumentRegion is
+ // removed
+ removeNode(text);
+ } else {
+ // notify the change
+ text.notifyValueChanged();
+ }
+ // if shared, continue to remove IStructuredDocumentRegion
+ // from them
+ if (isShared)
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+
+ ElementImpl element = (ElementImpl) next;
+ if (element.hasStartTag()) {
+ IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion();
+ if (flatNode != oldStructuredDocumentRegion) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ if (element.hasEndTag() || element.hasChildNodes()) {
+ element.setStartStructuredDocumentRegion(null);
+ removeStartTag(element);
+ } else {
+ removeNode(element);
+ }
+ } else {
+ Node child = element.getFirstChild();
+ if (child != null) {
+ this.context.setNextNode(child);
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+
+ if (!element.hasEndTag()) {
+ // implicit element
+ removeNode(element);
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+
+ IStructuredDocumentRegion flatNode = element.getEndStructuredDocumentRegion();
+ if (flatNode != oldStructuredDocumentRegion) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ removeNode(element);
+ }
+ return;
+ }
+
+ Node parent = this.context.getParentNode();
+ if (parent == null || parent.getNodeType() != Node.ELEMENT_NODE) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+
+ ElementImpl end = (ElementImpl) parent;
+ if (end.hasEndTag()) {
+ IStructuredDocumentRegion flatNode = end.getEndStructuredDocumentRegion();
+ if (flatNode != oldStructuredDocumentRegion) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ if (!end.hasStartTag() && !end.hasChildNodes()) {
+ this.context.setNextNode(end);
+ removeNode(end);
+ } else {
+ end.setEndStructuredDocumentRegion(null);
+ removeEndTag(end);
+ }
+ return;
+ }
+
+ next = (NodeImpl) end.getNextSibling();
+ if (next != null) {
+ this.context.setNextNode(next);
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+
+ parent = (NodeImpl) end.getParentNode();
+ if (parent != null) {
+ this.context.setParentNode(parent);
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+ }
+
+ /**
+ * replaceRegions method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ * @param newRegions
+ * java.util.Vector
+ * @param oldRegions
+ * java.util.Vector
+ */
+ void replaceRegions(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) {
+ if (flatNode == null)
+ return;
+ if (this.document == null)
+ return;
+ this.context = new XMLModelContext(this.document);
+
+ // optimize typical cases
+ String regionType = StructuredDocumentRegionUtil.getFirstRegionType(flatNode);
+ if (regionType == XMLRegionContext.XML_TAG_OPEN) {
+ changeStartTag(flatNode, newRegions, oldRegions);
+ } else if (regionType == XMLRegionContext.XML_END_TAG_OPEN) {
+ changeEndTag(flatNode, newRegions, oldRegions);
+ } else {
+ changeStructuredDocumentRegion(flatNode);
+ }
+ }
+
+ /**
+ * replaceStructuredDocumentRegions method
+ *
+ * @param newStructuredDocumentRegions
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegionList
+ * @param oldStructuredDocumentRegions
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegionList
+ */
+ void replaceStructuredDocumentRegions(IStructuredDocumentRegionList newStructuredDocumentRegions, IStructuredDocumentRegionList oldStructuredDocumentRegions) {
+ if (this.document == null)
+ return;
+ this.context = new XMLModelContext(this.document);
+
+ int newCount = (newStructuredDocumentRegions != null ? newStructuredDocumentRegions.getLength() : 0);
+ int oldCount = (oldStructuredDocumentRegions != null ? oldStructuredDocumentRegions.getLength() : 0);
+
+ if (oldCount > 0) {
+ setupContext(oldStructuredDocumentRegions.item(0));
+ // Node startParent = this.context.getParentNode();
+
+ Enumeration e = oldStructuredDocumentRegions.elements();
+ while (e.hasMoreElements()) {
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement();
+ if (flatNode == null)
+ continue;
+ removeStructuredDocumentRegion(flatNode);
+ }
+ } else {
+ if (newCount == 0)
+ return;
+ setupContext(newStructuredDocumentRegions.item(0));
+ }
+ // make sure the parent is set to deepest level
+ // when end tag has been removed
+ this.context.setLast();
+
+ if (newCount > 0) {
+ Enumeration e = newStructuredDocumentRegions.elements();
+ while (e.hasMoreElements()) {
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement();
+ if (flatNode == null)
+ continue;
+ insertStructuredDocumentRegion(flatNode);
+ }
+ }
+
+ cleanupText();
+ cleanupEndTag();
+ }
+
+ /**
+ * setupContext method
+ *
+ * @param flatNode
+ * com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ private void setupContext(IStructuredDocumentRegion startStructuredDocumentRegion) {
+ int offset = startStructuredDocumentRegion.getStart();
+ if (offset < 0)
+ return;
+ NodeImpl root = (NodeImpl) this.context.getRootNode();
+ if (root == null)
+ return;
+
+ if (offset == 0) {
+ // at the beggining of document
+ Node child = root.getFirstChild();
+ if (child != null)
+ this.context.setNextNode(child);
+ else
+ this.context.setParentNode(root);
+ return;
+ }
+
+ NodeImpl node = (NodeImpl) root.getNodeAt(offset);
+ if (node == null) {
+ // might be at the end of document
+ this.context.setParentNode(root);
+ this.context.setLast();
+ return;
+ }
+
+ if (offset == node.getStartOffset()) {
+ this.context.setNextNode(node);
+ return;
+ }
+
+ if (node.getNodeType() == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) node;
+ Text nextText = text.splitText(startStructuredDocumentRegion);
+ // notify the change
+ text.notifyValueChanged();
+ if (nextText == null)
+ return; // error
+ this.context.setNextNode(nextText);
+ return;
+ }
+
+ for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (offset >= ((NodeImpl) child).getEndOffset())
+ continue;
+ this.context.setNextNode(child);
+ return;
+ }
+ this.context.setParentNode(node);
+ this.context.setLast();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java
new file mode 100644
index 0000000000..c9cab984c8
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java
@@ -0,0 +1,1647 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.document;
+
+
+
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.xml.core.document.JSPTag;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLGenerator;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+
+/**
+ * XMLModelUpdater class
+ */
+public class XMLModelUpdater implements XMLJSPRegionContexts {
+ private int diff = 0;
+ private int gapLength = 0;
+ private int gapOffset = 0;
+ private IStructuredDocumentRegion gapStructuredDocumentRegion = null;
+ private XMLGenerator generator = null;
+ private XMLModelImpl model = null;
+ private NodeImpl nextNode = null;
+ private NodeImpl parentNode = null;
+
+ protected XMLModelUpdater(XMLModelImpl model) {
+ super();
+
+ if (model != null) {
+ this.model = model;
+ this.generator = model.getGenerator();
+ }
+ }
+
+ /**
+ * changeAttrValue method
+ *
+ * @param attrNode
+ * org.w3c.dom.Attr
+ */
+ private void changeAttrName(Attr attrNode) {
+ if (attrNode == null)
+ return;
+
+ AttrImpl attr = (AttrImpl) attrNode;
+ ElementImpl element = (ElementImpl) attr.getOwnerElement();
+ if (element == null)
+ return;
+
+ if (element.isCommentTag()) {
+ changeStartTag(element);
+ return;
+ }
+
+ int offset = element.getStartOffset();
+ int start = offset;
+ int end = offset;
+
+ String name = attr.getName();
+ if (name == null)
+ name = new String();
+ ITextRegion nameRegion = attr.getNameRegion();
+ if (nameRegion == null)
+ return; // error
+ start += nameRegion.getStart();
+ // use getTextEnd() because getEnd() may include the tailing spaces
+ end += nameRegion.getTextEnd();
+
+ replaceSource(name, start, end);
+ }
+
+ /**
+ * changeAttrValue method
+ *
+ * @param attrNode
+ * org.w3c.dom.Attr
+ */
+ private void changeAttrValue(Attr attrNode) {
+ if (attrNode == null)
+ return;
+
+ AttrImpl attr = (AttrImpl) attrNode;
+ ElementImpl element = (ElementImpl) attr.getOwnerElement();
+ if (element == null)
+ return;
+
+ if (element.isCommentTag()) {
+ changeStartTag(element);
+ return;
+ }
+
+ int offset = element.getStartOffset();
+ int start = offset;
+ int end = offset;
+
+ String value = null;
+ ITextRegion valueRegion = attr.getValueRegion();
+ if (valueRegion != null) {
+ char quote = 0; // no quote preference
+ // DW: 4/16/2003 due to change in structuredDocument ... we need a
+ // flatnode to
+ // get at region values. For now I'll assume this is always the
+ // first
+ // flatnode .. may need to make smarter later (e.g. to search for
+ // the flatnode that this.valueRegion belongs to.
+ IStructuredDocumentRegion documentRegion = element.getFirstStructuredDocumentRegion();
+ String oldValue = documentRegion.getText(valueRegion);
+ if (oldValue != null && oldValue.length() > 0) {
+ char firstChar = oldValue.charAt(0);
+ if (firstChar == '"' || firstChar == '\'') {
+ quote = firstChar;
+ }
+ }
+
+ ITextRegion startRegion = valueRegion;
+
+ value = this.generator.generateAttrValue(attr, quote);
+ if (value == null) {
+ value = new String();
+ // remove equal too
+ ITextRegion equalRegion = attr.getEqualRegion();
+ if (equalRegion != null)
+ startRegion = equalRegion;
+ }
+ attr.setValueRegion(valueRegion); // reset value
+
+ start += startRegion.getStart();
+ // use getTextEnd() because getEnd() may include the tailing
+ // spaces
+ end += valueRegion.getTextEnd();
+ } else {
+ ITextRegion equalRegion = attr.getEqualRegion();
+
+ value = this.generator.generateAttrValue(attr);
+ if (value == null) {
+ if (equalRegion == null)
+ return; // nothng to do
+ value = new String();
+ // remove equal
+ start += equalRegion.getStart();
+ end += equalRegion.getTextEnd();
+ } else {
+ if (equalRegion != null) {
+ // use getTextEnd() because getEnd() may include the
+ // tailing spaces
+ start += equalRegion.getTextEnd();
+ } else {
+ ITextRegion nameRegion = attr.getNameRegion();
+ if (nameRegion == null)
+ return; // must never happen
+ // use getTextEnd() because getEnd() may include the
+ // tailing spaces
+ start += nameRegion.getTextEnd();
+ value = '=' + value;
+ }
+ end = start;
+ }
+ }
+
+ replaceSource(value, start, end);
+ }
+
+ /**
+ */
+ void changeEndTag(Element element) {
+ String source = this.generator.generateEndTag(element);
+ if (source == null)
+ return;
+ int length = source.length();
+ if (length == 0)
+ return;
+
+ ElementImpl impl = (ElementImpl) element;
+ int offset = impl.getEndStartOffset();
+ int start = offset;
+ int end = offset;
+ if (impl.hasEndTag()) {
+ end = impl.getEndOffset();
+ this.gapStructuredDocumentRegion = impl.getEndStructuredDocumentRegion();
+ impl.setEndStructuredDocumentRegion(new StructuredDocumentRegionProxy(offset, length));
+ }
+
+ replaceSource(source, start, end);
+ }
+
+ /**
+ * changeName method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ void changeName(Node node) {
+ if (node == null)
+ return;
+ if (getStructuredDocument() == null)
+ return;
+
+ // support changing name of attribute for setPrefix()
+ short nodeType = node.getNodeType();
+ if (nodeType == Node.ATTRIBUTE_NODE) {
+ changeAttrName((Attr) node);
+ return;
+ }
+
+ // not supported
+ return;
+ }
+
+ void changeRegion(IStructuredDocumentRegion flatNode, ITextRegion region) {
+ // future_TODO: optimize
+
+ NodeImpl root = (NodeImpl) this.model.getDocument();
+ this.parentNode = root;
+ this.nextNode = (NodeImpl) root.getFirstChild();
+
+ removeGapStructuredDocumentRegion(flatNode);
+ insertGapStructuredDocumentRegionBefore(flatNode.getStart());
+ changeStructuredDocumentRegion(flatNode);
+ insertGapStructuredDocumentRegionAfter(flatNode.getEnd());
+ }
+
+ /**
+ * This is a fallback method to regenerate the start tag.
+ */
+ void changeStartTag(Element element) {
+ if (element == null)
+ return;
+ ElementImpl impl = (ElementImpl) element;
+
+ if (!impl.hasStartTag() && !impl.hasEndTag()) {
+ // need to generate the start and the end tags
+ Node parent = element.getParentNode();
+ if (parent != null) {
+ replaceChild(parent, element, element);
+ return;
+ }
+ // else error
+ }
+
+ String source = this.generator.generateStartTag(element);
+ if (source == null)
+ return;
+ int length = source.length();
+ if (length == 0)
+ return;
+
+ int offset = impl.getStartOffset();
+ int start = offset;
+ int end = offset;
+ if (impl.hasStartTag()) {
+ end = impl.getStartEndOffset();
+ this.gapStructuredDocumentRegion = impl.getStartStructuredDocumentRegion();
+ }
+ impl.setStartStructuredDocumentRegion(new StructuredDocumentRegionProxy(offset, length));
+
+ replaceSource(source, start, end);
+ }
+
+ private void changeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ if (oldStructuredDocumentRegion == null)
+ return; // error
+ if (this.parentNode == null)
+ return; // error
+
+ int oldOffset = oldStructuredDocumentRegion.getStart();
+ int oldEnd = oldStructuredDocumentRegion.getEnd();
+ boolean isEndTag = false;
+
+ // find owner node
+ NodeImpl ownerNode = null;
+ while (this.parentNode != null) {
+ if (this.nextNode != null) {
+ IStructuredDocumentRegion nextStructuredDocumentRegion = this.nextNode.getStructuredDocumentRegion();
+ if (nextStructuredDocumentRegion != null) {
+ if (nextStructuredDocumentRegion == oldStructuredDocumentRegion) {
+ ownerNode = this.nextNode;
+ break;
+ }
+ int nextOffset = nextStructuredDocumentRegion.getStart();
+ if (nextOffset == oldOffset) { // found
+ ownerNode = this.nextNode;
+ break;
+ }
+ if (this.nextNode.getNodeType() == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) this.nextNode;
+ if (text.hasStructuredDocumentRegion(oldStructuredDocumentRegion)) {
+ ownerNode = this.nextNode;
+ break;
+ }
+ int nextEnd = nextStructuredDocumentRegion.getEnd();
+ if (nextOffset < oldEnd && nextEnd > oldOffset) {
+ ownerNode = this.nextNode;
+ break;
+ }
+ }
+ }
+
+ Node child = this.nextNode.getFirstChild();
+ if (child != null) {
+ this.parentNode = this.nextNode;
+ this.nextNode = (NodeImpl) child;
+ continue;
+ }
+
+ if (this.nextNode.getNodeType() == Node.ELEMENT_NODE) {
+ this.parentNode = this.nextNode;
+ this.nextNode = null;
+ continue;
+ }
+
+ this.nextNode = (NodeImpl) this.nextNode.getNextSibling();
+ if (this.nextNode != null)
+ continue;
+ }
+
+ if (this.parentNode.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) this.parentNode;
+ IStructuredDocumentRegion endStructuredDocumentRegion = element.getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null) {
+ if (endStructuredDocumentRegion == oldStructuredDocumentRegion) {
+ ownerNode = this.parentNode;
+ isEndTag = true;
+ break;
+ }
+ int endOffset = endStructuredDocumentRegion.getStart();
+ if (endOffset == oldOffset) { // found
+ ownerNode = this.parentNode;
+ isEndTag = true;
+ break;
+ }
+ }
+ }
+
+ this.nextNode = (NodeImpl) this.parentNode.getNextSibling();
+ this.parentNode = (NodeImpl) this.parentNode.getParentNode();
+ }
+ if (ownerNode == null)
+ throw new StructuredDocumentRegionManagementException();
+
+ short nodeType = ownerNode.getNodeType();
+ if (nodeType == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) ownerNode;
+ if (isEndTag) {
+ element.setEndStructuredDocumentRegion(oldStructuredDocumentRegion);
+ } else {
+ element.setStartStructuredDocumentRegion(oldStructuredDocumentRegion);
+ updateAttrRegions(element, oldStructuredDocumentRegion);
+ }
+ } else if (nodeType == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) ownerNode;
+
+ IStructuredDocumentRegion flatNode = text.getStructuredDocumentRegion();
+ if (flatNode == oldStructuredDocumentRegion) {
+ int newOffset = oldOffset;
+ int newEnd = oldEnd;
+ if (oldOffset == this.gapOffset) {
+ newOffset += this.diff;
+ } else {
+ newEnd = this.gapOffset;
+ }
+ int newLength = newEnd - newOffset;
+ IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(newOffset, newLength, oldStructuredDocumentRegion);
+ text.setStructuredDocumentRegion(newStructuredDocumentRegion);
+
+ if (oldEnd > newEnd) {
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ changeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ }
+ return;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ int offset = proxy.getOffset();
+ int end = offset + proxy.getLength();
+ if (proxy.getStructuredDocumentRegion() == null) {
+ if (offset == oldOffset && end == oldEnd) {
+ text.setStructuredDocumentRegion(oldStructuredDocumentRegion);
+ } else {
+ if (end > oldEnd) {
+ StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer();
+ container.appendStructuredDocumentRegion(oldStructuredDocumentRegion);
+ proxy.setOffset(oldEnd);
+ proxy.setLength(end - oldEnd);
+ container.appendStructuredDocumentRegion(proxy);
+ text.setStructuredDocumentRegion(container);
+ } else {
+ proxy.setStructuredDocumentRegion(oldStructuredDocumentRegion);
+
+ if (end < oldEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ changeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ }
+ }
+ }
+ return;
+ }
+
+ if (offset >= this.gapOffset) {
+ proxy.setOffset(offset + this.diff);
+ end += this.diff;
+ }
+ if (end < oldEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ changeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+ } else if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue; // error
+ if (content == oldStructuredDocumentRegion) {
+ int newOffset = oldOffset;
+ int newEnd = oldEnd;
+ if (oldOffset == this.gapOffset) {
+ newOffset += this.diff;
+ } else {
+ newEnd = this.gapOffset;
+ }
+ int newLength = newEnd - newOffset;
+ IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(newOffset, newLength, oldStructuredDocumentRegion);
+ container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i);
+
+ if (oldEnd > newEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ changeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ }
+ return;
+ }
+
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ int offset = proxy.getOffset();
+ int end = offset + proxy.getLength();
+ if (end <= oldOffset)
+ continue;
+ if (proxy.getStructuredDocumentRegion() == null) {
+ if (offset == oldOffset && end == oldEnd) {
+ container.replaceStructuredDocumentRegion(oldStructuredDocumentRegion, i);
+ } else {
+ if (end > oldEnd) {
+ container.insertStructuredDocumentRegion(oldStructuredDocumentRegion, i);
+ proxy.setOffset(oldEnd);
+ proxy.setLength(end - oldEnd);
+ } else {
+ proxy.setStructuredDocumentRegion(oldStructuredDocumentRegion);
+
+ if (end < oldEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ changeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ }
+ }
+ }
+ return;
+ }
+
+ if (offset >= this.gapOffset) {
+ proxy.setOffset(offset + this.diff);
+ end += this.diff;
+ }
+ if (end < oldEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ changeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+ }
+ }
+ } else {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ } else {
+ ownerNode.setStructuredDocumentRegion(oldStructuredDocumentRegion);
+ }
+ }
+
+ /**
+ */
+ private void changeTextData(Text text) {
+ if (text == null)
+ return;
+
+ String source = this.generator.generateSource(text);
+ if (source == null)
+ source = new String();
+ int length = source.length();
+
+ TextImpl impl = (TextImpl) text;
+ int start = impl.getStartOffset();
+ int end = impl.getEndOffset();
+ int offset = start;
+
+ // make sure previous tag is closed
+ Node prev = text.getPreviousSibling();
+ if (prev != null) {
+ String preTag = getCloseTag((XMLNode) prev);
+ if (preTag != null && preTag.length() > 0) {
+ offset += preTag.length();
+ source = preTag + source;
+ }
+ } else {
+ Node parent = text.getParentNode();
+ if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) parent;
+ String preTag = getStartCloseTag(element);
+ if (preTag != null && preTag.length() > 0) {
+ offset += preTag.length();
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(preTag);
+ buffer.append(source);
+ if (text.getNextSibling() == null && !element.hasEndTag() && (element.isJSPContainer() || element.isCDATAContainer())) {
+ // need to generate the end tag
+ String postTag = this.generator.generateEndTag(element);
+ if (postTag != null) {
+ int postLength = postTag.length();
+ if (postLength > 0) {
+ buffer.append(postTag);
+ int postOffset = offset + length;
+ IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(postOffset, postLength);
+ element.setEndStructuredDocumentRegion(flatNode);
+ }
+ }
+ }
+ source = buffer.toString();
+ }
+ }
+ }
+
+ this.gapStructuredDocumentRegion = impl.getStructuredDocumentRegion();
+ IStructuredDocumentRegion newStructuredDocumentRegion = null;
+ if (length > 0)
+ newStructuredDocumentRegion = new StructuredDocumentRegionProxy(offset, length);
+ impl.setStructuredDocumentRegion(newStructuredDocumentRegion);
+
+ replaceSource(source, start, end);
+ }
+
+ /**
+ * changeValue method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ void changeValue(Node node) {
+ if (node == null)
+ return;
+ if (getStructuredDocument() == null)
+ return;
+
+ short nodeType = node.getNodeType();
+ if (nodeType == Node.TEXT_NODE) {
+ changeTextData((Text) node);
+ return;
+ }
+ if (nodeType == Node.ATTRIBUTE_NODE) {
+ changeAttrValue((Attr) node);
+ return;
+ }
+ if (nodeType == Node.ELEMENT_NODE) {
+ changeStartTag((Element) node);
+ return;
+ }
+
+ String source = this.generator.generateSource(node);
+ if (source == null)
+ source = new String();
+ int length = source.length();
+
+ NodeImpl impl = (NodeImpl) node;
+ int start = impl.getStartOffset();
+ int end = impl.getEndOffset();
+
+ this.gapStructuredDocumentRegion = impl.getStructuredDocumentRegion();
+ IStructuredDocumentRegion flatNode = null;
+ if (length > 0)
+ flatNode = new StructuredDocumentRegionProxy(start, length);
+ impl.setStructuredDocumentRegion(flatNode);
+
+ replaceSource(source, start, end);
+ }
+
+ /**
+ */
+ private String getAttrValueClose(XMLElement element) {
+ if (element == null)
+ return null;
+
+ IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion();
+ if (flatNode == null)
+ return null;
+ ITextRegion region = StructuredDocumentRegionUtil.getLastRegion(flatNode);
+ if (region == null || region.getType() != XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)
+ return null;
+ String value = flatNode.getText(region);
+ if (value == null)
+ return null;
+ int length = value.length();
+ if (length == 0)
+ return null;
+
+ // check open JSP tag
+ boolean closeJSPTag = false;
+ int offset = value.indexOf(JSPTag.TAG_OPEN);
+ while (offset >= 0) {
+ offset = value.indexOf(JSPTag.TAG_CLOSE, offset + 2);
+ if (offset < 0) {
+ closeJSPTag = true;
+ break;
+ }
+ offset = value.indexOf(JSPTag.TAG_OPEN, offset + 2);
+ }
+
+ // check quote
+ boolean closeQuote = false;
+ char firstChar = value.charAt(0);
+ if (firstChar == '"' || firstChar == '\'') {
+ if (closeJSPTag || length == 1 || value.charAt(length - 1) != firstChar) {
+ closeQuote = true;
+ }
+ }
+
+ if (!closeJSPTag && !closeQuote)
+ return null;
+
+ StringBuffer buffer = new StringBuffer();
+ if (closeJSPTag)
+ buffer.append(JSPTag.TAG_CLOSE);
+ if (closeQuote)
+ buffer.append(firstChar);
+ return buffer.toString();
+ }
+
+ /**
+ * Gather close tags recursively.
+ */
+ private String getCloseTag(XMLNode node) {
+ if (node == null || node.isClosed())
+ return null;
+
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ return this.generator.generateCloseTag(node);
+ }
+
+ ElementImpl element = (ElementImpl) node;
+ if (element.hasEndTag()) {
+ // end tag is not closed
+ return this.generator.generateCloseTag(element);
+ }
+
+ // no end tag
+ int offset = element.getEndOffset();
+ StringBuffer buffer = new StringBuffer();
+
+ XMLNode lastChild = (XMLNode) element.getLastChild();
+ if (lastChild == null) {
+ if (!element.isStartTagClosed()) {
+ if (element.preferEmptyTag())
+ element.setEmptyTag(true);
+ String closeTag = getStartCloseTag(element);
+ if (closeTag != null) {
+ int length = closeTag.length();
+ if (length > 0) {
+ buffer.append(closeTag);
+ offset += length;
+ }
+ }
+ }
+ } else {
+ String closeTag = getCloseTag(lastChild);
+ if (closeTag != null) {
+ int length = closeTag.length();
+ if (length > 0) {
+ buffer.append(closeTag);
+ offset += length;
+ }
+ }
+ }
+
+ String endTag = this.generator.generateEndTag(element);
+ if (endTag != null) {
+ int length = endTag.length();
+ if (length > 0) {
+ buffer.append(endTag);
+ IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(offset, length);
+ element.setEndStructuredDocumentRegion(flatNode);
+ }
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ */
+ private String getStartCloseTag(XMLElement element) {
+ if (element == null || element.isStartTagClosed())
+ return null;
+
+ StringBuffer buffer = new StringBuffer();
+ String attrValueClose = getAttrValueClose(element);
+ if (attrValueClose != null)
+ buffer.append(attrValueClose);
+ String closeTag = this.generator.generateCloseTag(element);
+ if (closeTag != null)
+ buffer.append(closeTag);
+ return buffer.toString();
+ }
+
+ private IStructuredDocument getStructuredDocument() {
+ if (model == null)
+ return null;
+ return model.getStructuredDocument();
+ }
+
+ /**
+ */
+ void initialize() {
+ this.gapStructuredDocumentRegion = null;
+ this.gapOffset = 0;
+ this.gapLength = 0;
+ this.diff = 0;
+ this.parentNode = null;
+ this.nextNode = null;
+ }
+
+ private void insertGapStructuredDocumentRegionAfter(int endOffset) {
+ if (this.gapStructuredDocumentRegion == null)
+ return;
+
+ if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) this.gapStructuredDocumentRegion;
+ IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion();
+ if (flatNode != null)
+ insertStructuredDocumentRegion(flatNode);
+ } else if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) this.gapStructuredDocumentRegion;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue;
+ if (content.getStart() < endOffset)
+ continue;
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion();
+ if (flatNode != null)
+ insertStructuredDocumentRegion(flatNode);
+ } else {
+ insertStructuredDocumentRegion(content);
+ }
+ }
+ } else {
+ insertStructuredDocumentRegion(this.gapStructuredDocumentRegion);
+ }
+ }
+
+ private void insertGapStructuredDocumentRegionBefore(int startOffset) {
+ if (this.gapStructuredDocumentRegion == null)
+ return;
+
+ if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) this.gapStructuredDocumentRegion;
+ IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion();
+ if (flatNode != null)
+ insertStructuredDocumentRegion(flatNode);
+ } else if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) this.gapStructuredDocumentRegion;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue;
+ if (content.getStart() >= startOffset)
+ return;
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion();
+ if (flatNode != null)
+ insertStructuredDocumentRegion(flatNode);
+ } else {
+ insertStructuredDocumentRegion(content);
+ }
+ }
+ } else {
+ insertStructuredDocumentRegion(this.gapStructuredDocumentRegion);
+ }
+ }
+
+ /**
+ */
+ private void insertStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion) {
+ if (newStructuredDocumentRegion == null)
+ return; // error
+ if (this.parentNode == null)
+ return; // error
+
+ int newOffset = newStructuredDocumentRegion.getStart();
+ int newEnd = newStructuredDocumentRegion.getEnd();
+ boolean isEndTag = false;
+
+ // find owner node
+ NodeImpl ownerNode = null;
+ while (this.parentNode != null) {
+ if (this.nextNode != null) {
+ IStructuredDocumentRegion nextStructuredDocumentRegion = this.nextNode.getStructuredDocumentRegion();
+ if (nextStructuredDocumentRegion != null) {
+ int nextOffset = nextStructuredDocumentRegion.getStart();
+ if (nextOffset == newOffset) { // found
+ ownerNode = this.nextNode;
+ break;
+ }
+ if (this.nextNode.getNodeType() == Node.TEXT_NODE) {
+ int nextEnd = nextStructuredDocumentRegion.getEnd();
+ if (nextOffset < newEnd && nextEnd > newOffset) {
+ ownerNode = this.nextNode;
+ break;
+ }
+ }
+ }
+
+ Node child = this.nextNode.getFirstChild();
+ if (child != null) {
+ this.parentNode = this.nextNode;
+ this.nextNode = (NodeImpl) child;
+ continue;
+ }
+
+ if (this.nextNode.getNodeType() == Node.ELEMENT_NODE) {
+ this.parentNode = this.nextNode;
+ this.nextNode = null;
+ continue;
+ }
+
+ this.nextNode = (NodeImpl) this.nextNode.getNextSibling();
+ if (this.nextNode != null)
+ continue;
+ }
+
+ if (this.parentNode.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) this.parentNode;
+ IStructuredDocumentRegion endStructuredDocumentRegion = element.getEndStructuredDocumentRegion();
+ if (endStructuredDocumentRegion != null) {
+ int endOffset = endStructuredDocumentRegion.getStart();
+ if (endOffset == newOffset) { // found
+ ownerNode = this.parentNode;
+ isEndTag = true;
+ break;
+ }
+ }
+ }
+
+ this.nextNode = (NodeImpl) this.parentNode.getNextSibling();
+ this.parentNode = (NodeImpl) this.parentNode.getParentNode();
+ }
+ if (ownerNode == null)
+ throw new StructuredDocumentRegionManagementException();
+
+ short nodeType = ownerNode.getNodeType();
+ if (nodeType == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) ownerNode;
+ if (isEndTag) {
+ element.setEndStructuredDocumentRegion(newStructuredDocumentRegion);
+ } else {
+ element.setStartStructuredDocumentRegion(newStructuredDocumentRegion);
+ updateAttrRegions(element, newStructuredDocumentRegion);
+ }
+ } else if (nodeType == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) ownerNode;
+ IStructuredDocumentRegion oldStructuredDocumentRegion = text.getStructuredDocumentRegion();
+ if (oldStructuredDocumentRegion == null) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ int oldOffset = oldStructuredDocumentRegion.getStart();
+ int oldEnd = oldStructuredDocumentRegion.getEnd();
+ if (oldOffset == newOffset && oldEnd == newEnd) {
+ text.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ return;
+ }
+
+ if (oldStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) oldStructuredDocumentRegion;
+ if (oldEnd > newEnd) {
+ StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer();
+ if (oldOffset == newOffset) {
+ container.appendStructuredDocumentRegion(newStructuredDocumentRegion);
+ } else {
+ StructuredDocumentRegionProxy newProxy = new StructuredDocumentRegionProxy();
+ newProxy.setOffset(oldOffset);
+ newProxy.setLength(newEnd - oldOffset);
+ newProxy.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ container.appendStructuredDocumentRegion(newProxy);
+ }
+ proxy.setOffset(newEnd);
+ proxy.setLength(oldEnd - newEnd);
+ container.appendStructuredDocumentRegion(proxy);
+ text.setStructuredDocumentRegion(container);
+ } else {
+ proxy.setStructuredDocumentRegion(newStructuredDocumentRegion);
+
+ if (oldEnd < newEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ insertStructuredDocumentRegion(newStructuredDocumentRegion);
+ }
+ }
+ return;
+ }
+
+ if (oldStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) oldStructuredDocumentRegion;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue; // error
+ int offset = content.getStart();
+ int end = content.getEnd();
+ if (end <= newOffset)
+ continue;
+ if (offset == newOffset && end == newEnd) {
+ container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i);
+ return;
+ }
+
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (end > newEnd) {
+ if (offset == newOffset) {
+ container.insertStructuredDocumentRegion(newStructuredDocumentRegion, i);
+ } else {
+ StructuredDocumentRegionProxy newProxy = new StructuredDocumentRegionProxy();
+ newProxy.setOffset(offset);
+ newProxy.setLength(newEnd - offset);
+ newProxy.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ container.insertStructuredDocumentRegion(newProxy, i);
+ }
+ proxy.setOffset(newEnd);
+ proxy.setLength(end - newEnd);
+ return;
+ } else {
+ proxy.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ if (end == newEnd)
+ return;
+ }
+ }
+ }
+
+ if (oldEnd < newEnd) { // to be shared
+ this.nextNode = (NodeImpl) text.getNextSibling();
+ insertStructuredDocumentRegion(newStructuredDocumentRegion);
+ }
+ return;
+ } else {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ } else {
+ ownerNode.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ }
+ }
+
+ private void removeGapStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ if (this.gapStructuredDocumentRegion == null)
+ return;
+
+ if (this.gapStructuredDocumentRegion == oldStructuredDocumentRegion) {
+ this.gapStructuredDocumentRegion = null;
+ return;
+ }
+
+ if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) this.gapStructuredDocumentRegion;
+ IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion();
+ if (flatNode == oldStructuredDocumentRegion)
+ this.gapStructuredDocumentRegion = null;
+ } else if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) this.gapStructuredDocumentRegion;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue;
+ if (content == oldStructuredDocumentRegion) {
+ if (count > 1)
+ container.removeStructuredDocumentRegion(i);
+ else
+ this.gapStructuredDocumentRegion = null;
+ return;
+ }
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ if (count > 1)
+ container.removeStructuredDocumentRegion(i);
+ else
+ this.gapStructuredDocumentRegion = null;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) {
+ if (oldStructuredDocumentRegion == null)
+ return; // error
+ if (this.parentNode == null)
+ return; // error
+
+ int gapEnd = this.gapOffset + this.gapLength;
+ int oldOffset = oldStructuredDocumentRegion.getStart();
+ int oldEnd = oldStructuredDocumentRegion.getEnd();
+ if (oldOffset >= this.gapOffset && oldEnd <= gapEnd)
+ return; // do nothing
+ int oldLength = oldEnd - oldOffset;
+ if (oldOffset >= gapEnd)
+ oldOffset += this.diff;
+
+ // find owner node
+ NodeImpl ownerNode = null;
+ ElementImpl ownerEndTag = null;
+ TextImpl ownerText = null;
+ while (this.parentNode != null) {
+ if (this.nextNode != null) {
+ if (this.nextNode.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ ownerNode = this.nextNode;
+ break;
+ }
+ if (this.nextNode.getNodeType() == Node.TEXT_NODE) {
+ TextImpl text = (TextImpl) this.nextNode;
+ if (text.hasStructuredDocumentRegion(oldStructuredDocumentRegion)) {
+ ownerNode = this.nextNode;
+ ownerText = text;
+ break;
+ }
+ }
+
+ Node child = this.nextNode.getFirstChild();
+ if (child != null) {
+ this.parentNode = this.nextNode;
+ this.nextNode = (NodeImpl) child;
+ continue;
+ }
+
+ if (this.nextNode.getNodeType() == Node.ELEMENT_NODE) {
+ this.parentNode = this.nextNode;
+ this.nextNode = null;
+ continue;
+ }
+
+ this.nextNode = (NodeImpl) this.nextNode.getNextSibling();
+ if (this.nextNode != null)
+ continue;
+ }
+
+ if (this.parentNode.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) this.parentNode;
+ if (element.getEndStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ ownerNode = this.parentNode;
+ ownerEndTag = element;
+ break;
+ }
+ }
+
+ this.nextNode = (NodeImpl) this.parentNode.getNextSibling();
+ this.parentNode = (NodeImpl) this.parentNode.getParentNode();
+ }
+ if (ownerNode == null)
+ throw new StructuredDocumentRegionManagementException();
+
+ if (ownerText != null) {
+ IStructuredDocumentRegion flatNode = ownerText.getStructuredDocumentRegion();
+ if (flatNode == oldStructuredDocumentRegion) {
+ IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(oldOffset, oldLength);
+ ownerText.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ return;
+ }
+
+ if (flatNode instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode;
+ if (proxy.getStructuredDocumentRegion() != oldStructuredDocumentRegion) {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ int offset = proxy.getOffset();
+ int end = offset + proxy.getLength();
+ if (offset >= this.gapOffset) {
+ proxy.setOffset(offset + this.diff);
+ }
+ proxy.setStructuredDocumentRegion(null);
+ if (end < oldEnd && (end < this.gapOffset || oldEnd > gapEnd)) { // has
+ // shared
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+ } else if (flatNode instanceof StructuredDocumentRegionContainer) {
+ StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode;
+ int count = container.getStructuredDocumentRegionCount();
+ for (int i = 0; i < count; i++) {
+ IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i);
+ if (content == null)
+ continue; // error
+ if (content == oldStructuredDocumentRegion) {
+ IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(oldOffset, oldLength);
+ container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i);
+ return;
+ }
+
+ if (content instanceof StructuredDocumentRegionProxy) {
+ StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content;
+ if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) {
+ int offset = proxy.getOffset();
+ int end = offset + proxy.getLength();
+ if (offset >= this.gapOffset) {
+ proxy.setOffset(offset + this.diff);
+ }
+ proxy.setStructuredDocumentRegion(null);
+ if (end < oldEnd && (end < this.gapOffset || oldEnd > gapEnd)) { // has
+ // shared
+ removeStructuredDocumentRegion(oldStructuredDocumentRegion);
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ throw new StructuredDocumentRegionManagementException();
+ }
+ } else {
+ IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(oldOffset, oldLength);
+ if (ownerEndTag != null) {
+ ownerEndTag.setEndStructuredDocumentRegion(newStructuredDocumentRegion);
+ } else {
+ ownerNode.setStructuredDocumentRegion(newStructuredDocumentRegion);
+ }
+ }
+ }
+
+ /**
+ * replaceAttr method
+ *
+ * @param ownerElement
+ * org.w3c.dom.Element
+ * @param newAttr
+ * org.w3c.dom.Attr
+ * @param oldAttr
+ * org.w3c.dom.Attr
+ */
+ void replaceAttr(Element ownerElement, Attr newAttr, Attr oldAttr) {
+ if (ownerElement == null)
+ return;
+ if (getStructuredDocument() == null)
+ return;
+
+ ElementImpl element = (ElementImpl) ownerElement;
+ if (!element.hasStartTag()) {
+ changeStartTag(element);
+ return;
+ }
+ if (element.isCommentTag()) {
+ changeStartTag(element);
+ return;
+ }
+
+ int offset = element.getStartOffset();
+ int start = offset;
+ int end = offset;
+
+ boolean insertSpace = false;
+ String attrValueClose = null;
+ if (oldAttr != null) {
+ AttrImpl impl = (AttrImpl) oldAttr;
+ ITextRegion nameRegion = impl.getNameRegion();
+ if (nameRegion == null)
+ return; // must never happen
+ ITextRegion lastRegion = impl.getValueRegion();
+ if (lastRegion != null) {
+ end += lastRegion.getEnd();
+ } else {
+ lastRegion = impl.getEqualRegion();
+ if (lastRegion != null) {
+ end += lastRegion.getEnd();
+ } else {
+ end += nameRegion.getEnd();
+ lastRegion = nameRegion;
+ }
+ }
+ // check there are extra space before the last attribute
+ IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion();
+ if (flatNode == null)
+ return; // must never happen
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return; // must never happen
+ ITextRegion prevRegion = null;
+ ITextRegion nextRegion = null;
+ for (int i = 0; i < regions.size(); i++) {
+ ITextRegion region = regions.get(i);
+ if (region == nameRegion) {
+ if (i > 0) {
+ prevRegion = regions.get(i - 1);
+ }
+ }
+ if (region == lastRegion) {
+ if (i + 1 < regions.size()) {
+ nextRegion = regions.get(i + 1);
+ }
+ break;
+ }
+ }
+ boolean isLastAttr = false;
+ if (nextRegion != null) {
+ String regionType = nextRegion.getType();
+ if (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == JSP_CLOSE || regionType == JSP_DIRECTIVE_CLOSE) {
+ isLastAttr = true;
+ }
+ }
+ if (isLastAttr && prevRegion != null) {
+ start += prevRegion.getTextEnd();
+ } else {
+ start += nameRegion.getStart();
+ }
+
+ // impl.resetRegions(ownerElement);
+ impl.resetRegions(element);
+ } else { // append attribute
+ IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion();
+ if (flatNode == null)
+ return; // must never happen
+
+ attrValueClose = getAttrValueClose(element);
+ if (attrValueClose != null && attrValueClose.length() > 0) {
+ insertSpace = true;
+ start = flatNode.getEndOffset();
+ end = start;
+ } else {
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return; // must never happen
+ int attrStart = 0;
+ for (int i = regions.size() - 1; i >= 0; i--) {
+ ITextRegion region = regions.get(i);
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == JSP_CLOSE || regionType == JSP_DIRECTIVE_CLOSE)
+ continue;
+ int regionEnd = region.getEnd();
+ if (regionEnd == region.getTextEnd())
+ insertSpace = true;
+ attrStart = regionEnd;
+ break;
+ }
+ if (attrStart == 0)
+ return; // not found, must never happen
+ start += attrStart;
+ end = start;
+ }
+ }
+
+ String source = null;
+ if (newAttr != null) {
+ int size = 2;
+ if (attrValueClose != null)
+ size += attrValueClose.length();
+ String name = this.generator.generateAttrName(newAttr);
+ if (name != null)
+ size += name.length();
+ String value = this.generator.generateAttrValue(newAttr);
+ if (value != null)
+ size += value.length();
+ StringBuffer buffer = new StringBuffer(size);
+ if (attrValueClose != null)
+ buffer.append(attrValueClose);
+ if (insertSpace)
+ buffer.append(' ');
+ buffer.append(name);
+ if (value != null) {
+ buffer.append('=');
+ buffer.append(value);
+ }
+ source = buffer.toString();
+ }
+
+ replaceSource(source, start, end);
+ }
+
+ /**
+ * replaceChild method
+ *
+ * @param parentNode
+ * org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ void replaceChild(Node parentNode, Node newChild, Node oldChild) {
+ if (parentNode == null)
+ return;
+ if (newChild == null && oldChild == null)
+ return;
+ if (getStructuredDocument() == null)
+ return;
+
+ int start = 0;
+ int end = 0;
+ String preTag = null;
+ String postTag = null;
+ ElementImpl postElement = null;
+ if (oldChild != null) {
+ NodeImpl node = (NodeImpl) oldChild;
+ start = node.getStartOffset();
+ end = node.getEndOffset();
+ if (oldChild.getNodeType() == Node.TEXT_NODE) {
+ this.gapStructuredDocumentRegion = node.getStructuredDocumentRegion();
+ }
+ node.resetStructuredDocumentRegions(); // reset values from
+ // IStructuredDocumentRegion
+ } else {
+ NodeImpl prev = (NodeImpl) newChild.getPreviousSibling();
+ if (prev != null) {
+ start = prev.getEndOffset();
+ end = start;
+ preTag = getCloseTag(prev);
+ } else {
+ // first child
+ NodeImpl next = (NodeImpl) newChild.getNextSibling();
+ if (next != null) {
+ start = next.getStartOffset();
+ end = start;
+ if (parentNode.getNodeType() == Node.ELEMENT_NODE) {
+ preTag = getStartCloseTag((XMLElement) parentNode);
+ }
+ } else {
+ // newly having a child
+ if (parentNode.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) parentNode;
+ if (element.isEmptyTag()) { // empty tag format
+ // need to generate the start and the end tags
+ end = element.getEndOffset();
+ start = end - 2; // for "/>"
+ element.setEmptyTag(false);
+ preTag = this.generator.generateCloseTag(element);
+ postTag = this.generator.generateEndTag(element);
+ postElement = element;
+ } else if (!element.hasStartTag()) {
+ start = element.getStartOffset();
+ end = start;
+ // invalid end tag or implicit tag
+ // need to generate the start tag
+ preTag = this.generator.generateStartTag(element);
+ if (preTag != null) {
+ int length = preTag.length();
+ if (length > 0) {
+ IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(start, length);
+ element.setStartStructuredDocumentRegion(flatNode);
+ }
+ }
+ if (!element.hasEndTag()) {
+ // implicit tag
+ // need to generate the end tags
+ postTag = this.generator.generateEndTag(element);
+ postElement = element;
+ }
+ } else {
+ start = element.getStartEndOffset();
+ end = start;
+ preTag = getStartCloseTag(element);
+ if (preTag != null && preTag.length() > 0) {
+ if (!element.hasEndTag() && (element.isJSPContainer() || element.isCDATAContainer())) {
+ // need to generate the end tag
+ postTag = this.generator.generateEndTag(element);
+ postElement = element;
+ }
+ }
+ }
+ }
+ // else might DOCUMENT_NODE, start and end are 0
+ }
+ }
+ }
+
+ String source = null;
+ if (newChild != null) {
+ StringBuffer buffer = new StringBuffer();
+ int offset = start;
+ if (preTag != null) {
+ int length = preTag.length();
+ if (length > 0) {
+ offset += length;
+ buffer.append(preTag);
+ }
+ }
+
+ NodeImpl node = (NodeImpl) newChild;
+ while (node != null) {
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) node;
+ if (element.preferEmptyTag())
+ element.setEmptyTag(true);
+ IStructuredDocumentRegion flatNode = null;
+ String startTag = this.generator.generateStartTag(element);
+ if (startTag != null) {
+ int length = startTag.length();
+ if (length > 0) {
+ buffer.append(startTag);
+ flatNode = new StructuredDocumentRegionProxy(offset, length);
+ offset += length;
+ }
+ }
+ element.setStartStructuredDocumentRegion(flatNode);
+ } else {
+ String content = this.generator.generateSource(node);
+ if (content == null)
+ content = new String();
+ int length = content.length();
+ IStructuredDocumentRegion flatNode = null;
+ if (length > 0) {
+ buffer.append(content);
+ flatNode = new StructuredDocumentRegionProxy(offset, length);
+ offset += length;
+ }
+ node.setStructuredDocumentRegion(flatNode);
+ }
+
+ NodeImpl child = (NodeImpl) node.getFirstChild();
+ if (child != null) {
+ node = child;
+ continue;
+ }
+
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ ElementImpl element = (ElementImpl) node;
+ IStructuredDocumentRegion flatNode = null;
+ String endTag = this.generator.generateEndTag(element);
+ if (endTag != null) {
+ int length = endTag.length();
+ if (length > 0) {
+ buffer.append(endTag);
+ flatNode = new StructuredDocumentRegionProxy(offset, length);
+ offset += length;
+ }
+ }
+ element.setEndStructuredDocumentRegion(flatNode);
+ }
+
+ while (node != null) {
+ if (node == newChild) {
+ node = null;
+ break;
+ }
+ NodeImpl next = (NodeImpl) node.getNextSibling();
+ if (next != null) {
+ node = next;
+ break;
+ }
+
+ node = (NodeImpl) node.getParentNode();
+ if (node.getNodeType() != Node.ELEMENT_NODE)
+ continue;
+ ElementImpl element = (ElementImpl) node;
+ IStructuredDocumentRegion flatNode = null;
+ String endTag = this.generator.generateEndTag(element);
+ if (endTag != null) {
+ int length = endTag.length();
+ if (length > 0) {
+ buffer.append(endTag);
+ flatNode = new StructuredDocumentRegionProxy(offset, length);
+ offset += length;
+ }
+ }
+ element.setEndStructuredDocumentRegion(flatNode);
+ }
+ }
+
+ if (postTag != null) {
+ int length = postTag.length();
+ if (length > 0) {
+ buffer.append(postTag);
+ if (postElement != null) {
+ IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(offset, length);
+ postElement.setEndStructuredDocumentRegion(flatNode);
+ }
+ }
+ }
+ source = buffer.toString();
+ }
+
+ if (start == end && (source == null || source.length() == 0)) {
+ // no thing changed
+ return;
+ }
+
+ replaceSource(source, start, end);
+ }
+
+ void replaceRegions(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) {
+ // future_TODO: optimize
+
+ NodeImpl root = (NodeImpl) this.model.getDocument();
+ this.parentNode = root;
+ this.nextNode = (NodeImpl) root.getFirstChild();
+
+ removeGapStructuredDocumentRegion(flatNode);
+ insertGapStructuredDocumentRegionBefore(flatNode.getStart());
+ changeStructuredDocumentRegion(flatNode);
+ insertGapStructuredDocumentRegionAfter(flatNode.getEnd());
+ }
+
+ /**
+ * Wraps IStructuredDocumentRegion.replaceText() and sets contextual
+ * information.
+ */
+ private void replaceSource(String source, int start, int end) {
+ int inserted = 0;
+ if (source == null)
+ source = new String();
+ else
+ inserted = source.length();
+ int removed = end - start;
+ if (inserted == 0 && removed == 0)
+ return;
+
+ this.gapOffset = start;
+ this.gapLength = removed;
+ this.diff = inserted - removed;
+ // Note: due to bug
+ // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3619
+ // for now assume "ignore readonly" region is ok -- assume DOM itself
+ // checks if
+ // ok to insert or not. In reality, we may have to make or "contains"
+ // method more
+ // better. Or, we may have to "perculate up" the parameter for clients
+ // to tell us programatically
+ // that its ok to insert/format in a read-only region.
+ getStructuredDocument().replaceText(this.model, this.gapOffset, this.gapLength, source, true);
+ }
+
+ void replaceStructuredDocumentRegions(IStructuredDocumentRegionList newStructuredDocumentRegions, IStructuredDocumentRegionList oldStructuredDocumentRegions) {
+ NodeImpl root = (NodeImpl) this.model.getDocument();
+
+ if (oldStructuredDocumentRegions != null) {
+ this.parentNode = root;
+ this.nextNode = (NodeImpl) root.getFirstChild();
+
+ Enumeration e = oldStructuredDocumentRegions.elements();
+ while (e.hasMoreElements()) {
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement();
+ if (flatNode == null)
+ continue;
+ removeStructuredDocumentRegion(flatNode);
+ removeGapStructuredDocumentRegion(flatNode);
+ }
+ }
+
+ if (newStructuredDocumentRegions != null) {
+ this.parentNode = root;
+ this.nextNode = (NodeImpl) root.getFirstChild();
+
+ IStructuredDocumentRegion lastStructuredDocumentRegion = null;
+ Enumeration e = newStructuredDocumentRegions.elements();
+ while (e.hasMoreElements()) {
+ IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement();
+ if (flatNode == null)
+ continue;
+ if (lastStructuredDocumentRegion == null)
+ insertGapStructuredDocumentRegionBefore(flatNode.getStart());
+ insertStructuredDocumentRegion(flatNode);
+ lastStructuredDocumentRegion = flatNode;
+ }
+ if (lastStructuredDocumentRegion != null) {
+ insertGapStructuredDocumentRegionAfter(lastStructuredDocumentRegion.getEnd());
+ } else {
+ insertGapStructuredDocumentRegionBefore(this.gapOffset);
+ // make sure to restore all backuped StructuredDocumentRegions
+ insertGapStructuredDocumentRegionAfter(this.gapOffset);
+ }
+ } else {
+ this.parentNode = root;
+ this.nextNode = (NodeImpl) root.getFirstChild();
+
+ insertGapStructuredDocumentRegionBefore(this.gapOffset);
+ // make sure to restore all backuped StructuredDocumentRegions
+ insertGapStructuredDocumentRegionAfter(this.gapOffset);
+ }
+ }
+
+ /**
+ */
+ private void updateAttrRegions(Element element, IStructuredDocumentRegion flatNode) {
+
+ // update attributes
+ ITextRegionList regions = flatNode.getRegions();
+ if (regions == null)
+ return;
+ NamedNodeMap attributes = element.getAttributes();
+ if (attributes == null)
+ return;
+ int index = -1;
+ AttrImpl attr = null;
+ Iterator e = regions.iterator();
+ while (e.hasNext()) {
+ ITextRegion region = (ITextRegion) e.next();
+ String regionType = region.getType();
+ if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) {
+ attr = (AttrImpl) attributes.item(++index);
+ if (attr != null) {
+ attr.setNameRegion(region);
+ // reset other regions
+ attr.setEqualRegion(null);
+ attr.setValueRegion(null);
+ }
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+ if (attr != null)
+ attr.setEqualRegion(region);
+ } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+ if (attr != null) {
+ attr.setValueRegion(region);
+ attr = null;
+ }
+ }
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java
new file mode 100644
index 0000000000..549752a77f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.filebuffers;
+
+import org.eclipse.core.filebuffers.IDocumentFactory;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.wst.sse.core.document.StructuredDocumentFactory;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser;
+
+
+
+public class DocumentFactoryForXML implements IDocumentFactory {
+
+ public DocumentFactoryForXML() {
+ super();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.filebuffers.IDocumentFactory#createDocument()
+ */
+ public IDocument createDocument() {
+ IStructuredDocument structuredDocument = StructuredDocumentFactory.getNewStructuredDocumentInstance(new XMLSourceParser());
+ return structuredDocument;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java
new file mode 100644
index 0000000000..1390a1f0fb
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.filebuffers;
+
+import org.eclipse.core.filebuffers.IDocumentSetupParticipant;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML;
+
+
+
+public class SetupParticipantForXML implements IDocumentSetupParticipant {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.filebuffers.IDocumentSetupParticipant#setup(org.eclipse.jface.text.IDocument)
+ */
+ public void setup(IDocument document) {
+ if (document != null) {
+ IDocumentPartitioner partitioner = new StructuredTextPartitionerForXML();
+ document.setDocumentPartitioner(partitioner);
+ partitioner.connect(document);
+
+ // setup empty model here? coordinated via model manager?
+
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java
new file mode 100644
index 0000000000..5442a10f0e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+
+
+import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.parser.IBlockedStructuredDocumentRegion;
+
+
+public class BlockStructuredDocumentRegion extends BasicStructuredDocumentRegion implements IBlockedStructuredDocumentRegion {
+
+ private String partitionType;
+
+ /**
+ * A BlockStructuredDocumentRegion is like a IStructuredDocumentRegion,
+ * but is the result of a "block scan".
+ */
+ public BlockStructuredDocumentRegion() {
+ super();
+ }
+
+ public String getPartitionType() {
+ if (partitionType == null) {
+ // eventually can look up surroundingTag name
+ // but this field is primarily entended for future
+ // extensibility. This may change.
+ //partitionType = "org.eclipse.wst.sse.core." + tagname;
+ }
+ return partitionType;
+ }
+
+ public void setPartitionType(String partitionType) {
+ this.partitionType = partitionType;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java
new file mode 100644
index 0000000000..e238281ff4
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java
@@ -0,0 +1,386 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.internal.Logger;
+import org.eclipse.wst.sse.core.internal.text.TextRegionListImpl;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionCollection;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+
+
+public class ContextRegionContainer implements ITextRegionContainer {
+ protected int length;
+ protected ITextRegionCollection parent;
+ protected ITextRegionList regions;
+ protected int start;
+ protected int textLength;
+ protected String type;
+
+ public ContextRegionContainer() {
+ super();
+ regions = new TextRegionListImpl();
+
+ }
+
+ /**
+ * these "deep" parenting is not normal, but just in case.
+ */
+ private IStructuredDocument _getParentDocument() {
+ // go up enough parents to get to document
+ ITextRegionCollection parent = getParent();
+ while (!(parent instanceof IStructuredDocumentRegion)) {
+ // would be an error not to be container, but
+ // won't check for it now
+ parent = ((ITextRegionContainer) parent).getParent();
+ }
+ return ((IStructuredDocumentRegion) parent).getParentDocument();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjust(int)
+ */
+ public void adjust(int i) {
+
+ start += i;
+ // I erroneously added length and textLength
+ // may want to rename this method to adjustStart
+ //length += i;
+ //textLength += i;
+
+ }
+
+ public void adjustLengthWith(int i) {
+ length += i;
+ }
+
+ public void adjustStart(int i) {
+ start += i;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ textLength += i;
+
+ }
+
+ public boolean containsOffset(int i) {
+
+ return getStartOffset() <= i && i < getEndOffset();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(com.ibm.sed.structured.text.ITextRegion,
+ * int)
+ */
+ public boolean containsOffset(ITextRegion containedRegion, int offset) {
+ return getStartOffset(containedRegion) <= offset && offset < getEndOffset(containedRegion);
+ }
+
+ /**
+ * This method is just to equate positions. clients may (will probably)
+ * still need to make calls to equate regions, parent, etc.
+ */
+ public void equatePositions(ITextRegion region) {
+ start = region.getStart();
+ length = region.getLength();
+ textLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return start + length;
+ }
+
+ public int getEndOffset() {
+ // our startOffset take into account our parent, and our start
+ return getStartOffset() + getLength();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getEndOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getEndOffset(ITextRegion containedRegion) {
+ return getStartOffset(containedRegion) + containedRegion.getLength();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getFirstRegion()
+ */
+ public ITextRegion getFirstRegion() {
+ return getRegions().get(0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getFullText()
+ */
+ public String getFullText() {
+ // CMVC > 252430, 245586
+ // unit test > com.ibm.sed.tests.other.UnitTests.testDeepEmbeddedJSP3
+ // this code modified on 6/25/03 (pa)
+
+ // String result = null;
+ // try {
+ // result = _getParentDocument().get(start, length);
+ // } catch (BadLocationException e) {
+ // Logger.logException("program error: unreachable exception", e);
+ // //$NON-NLS-1$
+ // }
+ // return result;
+ return getParent().getFullText(this);
+ }
+
+ public String getFullText(org.eclipse.wst.sse.core.text.ITextRegion aRegion) {
+ // Must be proxied here since aRegion should always be a child of
+ // *this* container and indexed from
+ // this container's offset
+ // try {
+ return parent.getFullText().substring(start + aRegion.getStart(), start + aRegion.getEnd());
+ //} catch (Exception e) {
+ //if (com.ibm.sed.util.Debug.debugStructuredDocument)
+ //e.printStackTrace();
+ //}
+ //return "";//$NON-NLS-1$
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getLastRegion()
+ */
+ public ITextRegion getLastRegion() {
+ return getRegions().get(getRegions().size() - 1);
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getNumberOfRegions()
+ */
+ public int getNumberOfRegions() {
+ return getRegions().size();
+ }
+
+ public ITextRegionCollection getParent() {
+ return parent;
+ }
+
+ /**
+ * The parameter offset refers to the overall offset in the document.
+ */
+ public ITextRegion getRegionAtCharacterOffset(int offset) {
+ ITextRegion result = null;
+ if (regions != null) {
+ // transform the requested offset to the "scale" that
+ // regions are stored in, which are all relative to the
+ // start point.
+ //int transformedOffset = offset - getStartOffset();
+ //
+ int length = getRegions().size();
+ for (int i = 0; i < length; i++) {
+ ITextRegion region = getRegions().get(i);
+ if (org.eclipse.wst.sse.core.util.Debug.debugStructuredDocument) {
+ System.out.println("region(s) in IStructuredDocumentRegion::getRegionAtCharacterOffset: " + region); //$NON-NLS-1$
+ System.out.println(" requested offset: " + offset); //$NON-NLS-1$
+ //System.out.println(" transformedOffset: " +
+ // transformedOffset); //$NON-NLS-1$
+ System.out.println(" region start: " + region.getStart()); //$NON-NLS-1$
+ System.out.println(" region end: " + region.getEnd()); //$NON-NLS-1$
+ System.out.println(" region type: " + region.getType()); //$NON-NLS-1$
+ System.out.println(" region class: " + region.getClass()); //$NON-NLS-1$
+
+ }
+ if ((getStartOffset(region) <= offset) && (offset < getEndOffset(region))) {
+ result = region;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ public ITextRegionList getRegions() {
+ return regions;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public int getStartOffset() {
+ return getParent().getStartOffset() + getStart();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getStartOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getStartOffset(ITextRegion containedRegion) {
+ return getStartOffset() + containedRegion.getStart();
+ }
+
+ /**
+ * same as getFullText for this region type ... do we need to take white
+ * space off?
+ */
+
+ public String getText() {
+ String result = null;
+ try {
+ IStructuredDocument parentDocument = _getParentDocument();
+ result = parentDocument.get(start, length);
+ } catch (BadLocationException e) {
+ Logger.logException("program error: unreachable exception", e); //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ public String getText(org.eclipse.wst.sse.core.text.ITextRegion aRegion) {
+ // Must be proxied here since aRegion should always be a child of
+ // *this* container and indexed from
+ // this container's offset
+ // com.ibm.sed.util.Assert.isTrue(regions.contains(aRegion));
+ //try {
+ return parent.getText().substring(start + aRegion.getStart(), start + aRegion.getTextEnd());
+ //} catch (Exception e) {
+ //if (com.ibm.sed.util.Debug.debugStructuredDocument)
+ //com.ibm.sed.util.Logger.log(e);
+ //}
+ // return ""; //$NON-NLS-1$
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#getTextEnd()
+ */
+ public int getTextEnd() {
+ // int result = 0;
+ // ITextRegion lastRegion = (ITextRegion) regions.get(regions.size() -
+ // 1);
+ // result = getStartOffset(lastRegion) + lastRegion.getTextLength();
+ // return result;
+ return start + textLength;
+ }
+
+ public int getTextEndOffset() {
+ ITextRegion region = regions.get(regions.size() - 1);
+ // our startOffset take into account our parent, and our start
+ // (pa) 10/4 changed to be based on text end
+ // it used to return incorrect value for embedded region containers
+ //
+
+ // TODO CRITICAL -- need to re-work this work around, so doesn't
+ // depend on XMLRegionContext
+ // // this is a workaround for 226823///////////
+ // for (int i = regions.size() - 1; i >= 0 && region.getType() ==
+ // XMLRegionContext.WHITE_SPACE; i--)
+ // region = (ITextRegion) regions.get(i);
+ // /////////////////////////////////////////////
+
+ return getStartOffset() + region.getTextEnd();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegionCollection#getTextEndOffset(com.ibm.sed.structured.text.ITextRegion)
+ */
+ public int getTextEndOffset(ITextRegion containedRegion) {
+ int result = 0;
+ if (regions != null) {
+ int length = getRegions().size();
+ for (int i = 0; i < length; i++) {
+ ITextRegion region = getRegions().get(i);
+ if (region == containedRegion) {
+ result = getStartOffset(region) + region.getTextEnd();
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ public int getTextLength() {
+ return textLength;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setLength(int i) {
+ length = i;
+ }
+
+ public void setParent(ITextRegionCollection parentRegion) {
+ parent = parentRegion;
+ }
+
+ public void setRegions(ITextRegionList containedRegions) {
+ regions = containedRegions;
+ }
+
+ public void setStart(int i) {
+ start = i;
+ }
+
+ public void setTextLength(int i) {
+ textLength = i;
+ }
+
+ public void setType(String string) {
+ type = string;
+ }
+
+ public String toString() {
+ String className = getClass().getName();
+ String shortClassName = className.substring(className.lastIndexOf(".") + 1); //$NON-NLS-1$
+ String result = "Container!!! " + shortClassName + "--> " + getType() + ": " + getStart() + "-" + getTextEnd() + (getTextEnd() != getEnd() ? ("/" + getEnd()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+ return result;
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ org.eclipse.wst.sse.core.events.RegionChangedEvent result = null;
+ // FUTURE_TO_DO: need to implement region level parsing in
+ // ITextRegionContainer::updateModel
+ // never being called?
+ return result;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java
new file mode 100644
index 0000000000..b871545643
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+
+
+/*
+ *
+ * A non-resizable class implementing the behavior of java.util.Stack, but
+ * directly for the <code> integer </code> primitive.
+ */
+import java.util.EmptyStackException;
+
+public class IntStack {
+ private int[] list = null;
+
+ private int size = 0;
+
+ public IntStack() {
+ this(100);
+ }
+
+ public IntStack(int maxdepth) {
+ super();
+ list = new int[maxdepth];
+ initialize();
+ }
+
+ public boolean empty() {
+ return size == 0;
+ }
+
+ public int get(int slot) {
+ return list[slot];
+ }
+
+ void initialize() {
+ for (int i = 0; i < list.length; i++)
+ list[i] = -1;
+ }
+
+ /**
+ * Returns the int at the top of the stack without removing it
+ *
+ * @return int at the top of this stack.
+ * @exception EmptyStackException
+ * when empty.
+ */
+ public int peek() {
+ if (size == 0)
+ throw new EmptyStackException();
+ return list[size - 1];
+ }
+
+ /**
+ * Removes and returns the int at the top of the stack
+ *
+ * @return int at the top of this stack.
+ * @exception EmptyStackException
+ * when empty.
+ */
+ public int pop() {
+ int value = peek();
+ list[size - 1] = -1;
+ size--;
+ return value;
+ }
+
+ /**
+ * Pushes an item onto the top of this stack.
+ *
+ * @param newValue -
+ * the int to be pushed onto this stack.
+ * @return the <code>newValue</code> argument.
+ */
+ public int push(int newValue) {
+ if (size == list.length) {
+ throw new StackOverflowError();
+ }
+ list[size++] = newValue;
+ return newValue;
+ }
+
+ public int size() {
+ return list.length;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java
new file mode 100644
index 0000000000..f9c4ab9e08
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+
+
+import org.eclipse.wst.sse.core.internal.parser.ContextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+
+
+public class RegionFactory {
+
+ public RegionFactory() {
+ super();
+ }
+
+ public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length) {
+ return this.createToken(parent, context, start, textLength, length, null, null);
+ }
+
+ public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length, String lang, String surroundingTag) {
+ ITextRegion newRegion = createToken(context, start, textLength, length);
+ // DW, 4/16/2003 token regions no longer have parents
+ //newRegion.setParent(parent);
+ return newRegion;
+ }
+
+ public ITextRegion createToken(String context, int start, int textLength, int length) {
+ return this.createToken(context, start, textLength, length, null, null);
+ }
+
+ public ITextRegion createToken(String context, int start, int textLength, int length, String lang, String surroundingTag) {
+ ITextRegion newRegion = new ContextRegion(context, start, textLength, length);
+ return newRegion;
+
+
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java
new file mode 100644
index 0000000000..1ff05a0a8b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java
@@ -0,0 +1,541 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+/* The following code was generated by JFlex 1.4 on 7/17/04 3:43 AM */
+
+/*nlsXXX*/
+package org.eclipse.wst.xml.core.internal.parser;
+
+
+
+/**
+ * This class is a scanner generated by <a href="http://www.jflex.de/">JFlex
+ * </a> 1.4 on 7/17/04 3:43 AM from the specification file
+ * <tt>XML10Names.jflex</tt>
+ */
+public final class XML10Names {
+
+ /** This character denotes the end of file */
+ private static final int YYEOF = -1;
+
+ /** initial size of the lookahead buffer */
+ private static final int ZZ_BUFFERSIZE = 2048;
+
+ /** lexical states */
+ private static final int YYINITIAL = 0;
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final String ZZ_CMAP_PACKED = "\11\0\1\1\1\2\2\0\1\1\22\0\1\1\14\0\1\0\2\0" + "\12\0\1\3\6\0\32\3\4\0\1\3\1\0\32\3\74\0\1\0" + "\10\0\27\3\1\0\37\3\1\0\72\3\2\0\13\3\2\0\10\3" + "\1\0\65\3\1\0\104\3\11\0\44\3\3\0\2\3\4\0\36\3" + "\70\0\131\3\22\0\7\3\16\0\2\0\56\0\106\0\32\0\2\0" + "\44\0\1\3\1\0\3\3\1\0\1\3\1\0\24\3\1\0\54\3" + "\1\0\7\3\3\0\1\3\1\0\1\3\1\0\1\3\1\0\1\3" + "\1\0\22\3\15\0\14\3\1\0\102\3\1\0\14\3\1\0\44\3" + "\1\0\4\0\11\0\65\3\2\0\2\3\2\0\2\3\3\0\34\3" + "\2\0\10\3\2\0\2\3\67\0\46\3\2\0\1\3\7\0\46\3" + "\12\0\21\0\1\0\27\0\1\0\3\0\1\0\1\0\1\0\2\0" + "\1\0\1\0\13\0\33\3\5\0\3\3\56\0\32\3\5\0\1\0" + "\12\3\10\0\15\0\12\0\6\0\1\0\107\3\2\0\5\3\1\0" + "\17\3\1\0\4\3\1\0\1\3\17\0\2\3\2\0\1\0\4\0" + "\2\0\12\0\u0207\0\3\0\1\0\65\3\2\0\1\0\1\3\20\0" + "\3\0\4\0\3\0\12\3\2\0\2\0\12\0\21\0\3\0\1\0" + "\10\3\2\0\2\3\2\0\26\3\1\0\7\3\1\0\1\3\3\0" + "\4\3\2\0\1\0\1\0\7\0\2\0\2\0\2\0\3\0\11\0" + "\1\0\4\0\2\3\1\0\3\3\2\0\2\0\12\0\2\3\20\0"
+ + "\1\0\2\0\6\3\4\0\2\3\2\0\26\3\1\0\7\3\1\0" + "\2\3\1\0\2\3\1\0\2\3\2\0\1\0\1\0\5\0\4\0" + "\2\0\2\0\3\0\13\0\4\3\1\0\1\3\7\0\12\0\2\0" + "\3\3\14\0\3\0\1\0\7\3\1\0\1\3\1\0\3\3\1\0" + "\26\3\1\0\7\3\1\0\2\3\1\0\5\3\2\0\1\0\1\3" + "\10\0\1\0\3\0\1\0\3\0\22\0\1\3\5\0\12\0\21\0" + "\3\0\1\0\10\3\2\0\2\3\2\0\26\3\1\0\7\3\1\0" + "\2\3\2\0\4\3\2\0\1\0\1\3\6\0\3\0\2\0\2\0" + "\3\0\10\0\2\0\4\0\2\3\1\0\3\3\4\0\12\0\22\0" + "\2\0\1\0\6\3\3\0\3\3\1\0\4\3\3\0\2\3\1\0" + "\1\3\1\0\2\3\3\0\2\3\3\0\3\3\3\0\10\3\1\0" + "\3\3\4\0\5\0\3\0\3\0\1\0\4\0\11\0\1\0\17\0" + "\11\0\21\0\3\0\1\0\10\3\1\0\3\3\1\0\27\3\1\0" + "\12\3\1\0\5\3\4\0\7\0\1\0\3\0\1\0\4\0\7\0" + "\2\0\11\0\2\3\4\0\12\0\22\0\2\0\1\0\10\3\1\0" + "\3\3\1\0\27\3\1\0\12\3\1\0\5\3\4\0\7\0\1\0" + "\3\0\1\0\4\0\7\0\2\0\7\0\1\3\1\0\2\3\4\0" + "\12\0\22\0\2\0\1\0\10\3\1\0\3\3\1\0\27\3\1\0" + "\20\3\4\0\6\0\2\0\3\0\1\0\4\0\11\0\1\0\10\0" + "\2\3\4\0\12\0\221\0\56\3\1\0\1\3\1\0\2\3\7\0"
+ + "\5\0\6\3\1\0\10\0\1\0\12\0\47\0\2\3\1\0\1\3" + "\2\0\2\3\1\0\1\3\2\0\1\3\6\0\4\3\1\0\7\3" + "\1\0\3\3\1\0\1\3\1\0\1\3\2\0\2\3\1\0\2\3" + "\1\0\1\3\1\0\2\3\6\0\1\0\2\0\1\3\2\0\5\3" + "\1\0\1\0\1\0\6\0\2\0\12\0\76\0\2\0\6\0\12\0" + "\13\0\1\0\1\0\1\0\1\0\1\0\4\0\2\0\10\3\1\0" + "\41\3\7\0\24\0\1\0\6\0\4\0\6\0\1\0\1\0\1\0" + "\25\0\3\0\7\0\1\0\1\0\346\0\46\3\12\0\47\3\11\0" + "\1\3\1\0\2\3\1\0\3\3\1\0\1\3\1\0\2\3\1\0" + "\5\3\51\0\1\3\1\0\1\3\1\0\1\3\13\0\1\3\1\0" + "\1\3\1\0\1\3\3\0\2\3\3\0\1\3\5\0\3\3\1\0" + "\1\3\1\0\1\3\1\0\1\3\1\0\1\3\3\0\2\3\3\0" + "\2\3\1\0\1\3\50\0\1\3\11\0\1\3\2\0\1\3\2\0" + "\2\3\7\0\2\3\1\0\1\3\1\0\7\3\50\0\1\3\4\0" + "\1\3\10\0\1\3\u0c06\0\234\3\4\0\132\3\6\0\26\3\2\0" + "\6\3\2\0\46\3\2\0\6\3\2\0\10\3\1\0\1\3\1\0" + "\1\3\1\0\1\3\1\0\37\3\2\0\65\3\1\0\7\3\1\0" + "\1\3\3\0\3\3\1\0\7\3\3\0\4\3\2\0\6\3\4\0" + "\15\3\5\0\3\3\1\0\7\3\323\0\15\0\4\0\1\0\104\0" + "\1\3\3\0\2\3\2\0\1\3\121\0\3\3\u0e82\0\1\0\1\0"
+ + "\1\3\31\0\11\3\6\0\1\0\5\0\13\0\124\3\4\0\2\0" + "\2\0\2\0\2\0\132\3\1\0\3\0\6\0\50\3\u1cd3\0\u51a6\3" + "\u0c5a\0\u2ba4\3\u285c\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final char[] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
+
+ /**
+ * Translates DFA states to action switch labels.
+ */
+ private static final int[] ZZ_ACTION = zzUnpackAction();
+
+ private static final String ZZ_ACTION_PACKED_0 = "\1\0\1\1\1\2\4\1";
+
+ private static int[] zzUnpackAction() {
+ int[] result = new int[7];
+ int offset = 0;
+ offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAction(String packed, int offset, int[] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do
+ result[j++] = value;
+ while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ private static final int[] ZZ_ROWMAP = zzUnpackRowMap();
+
+ private static final String ZZ_ROWMAP_PACKED_0 = "\0\0\0\4\0\10\0\14\0\20\0\24\0\30";
+
+ private static int[] zzUnpackRowMap() {
+ int[] result = new int[7];
+ int offset = 0;
+ offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackRowMap(String packed, int offset, int[] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int high = packed.charAt(i++) << 16;
+ result[j++] = high | packed.charAt(i++);
+ }
+ return j;
+ }
+
+ /**
+ * The transition table of the DFA
+ */
+ private static final int ZZ_TRANS[] = {1, 1, -1, 2, -1, -1, -1, -1, 2, 3, 4, 2, 2, 3, 4, 5, -1, 4, 4, 6, 5, 5, 4, 5, 6, 6, -1, 6,};
+
+ /* error codes */
+ private static final int ZZ_UNKNOWN_ERROR = 0;
+ private static final int ZZ_NO_MATCH = 1;
+ private static final int ZZ_PUSHBACK_2BIG = 2;
+
+ /* error messages for the codes above */
+ private static final String ZZ_ERROR_MSG[] = {"Unkown internal scanner error", "Error: could not match input", "Error: pushback value was too large"};
+
+ /**
+ * ZZ_ATTRIBUTE[aState] contains the attributes of state
+ * <code>aState</code>
+ */
+ private static final int[] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+ private static final String ZZ_ATTRIBUTE_PACKED_0 = "\1\0\1\11\5\1";
+
+ private static int[] zzUnpackAttribute() {
+ int[] result = new int[7];
+ int offset = 0;
+ offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAttribute(String packed, int offset, int[] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do
+ result[j++] = value;
+ while (--count > 0);
+ }
+ return j;
+ }
+
+ /** the input device */
+ private java.io.Reader zzReader;
+
+ /** the current state of the DFA */
+ private int zzState;
+
+ /** the current lexical state */
+ private int zzLexicalState = YYINITIAL;
+
+ /**
+ * this buffer contains the current text to be matched and is the source
+ * of the yytext() string
+ */
+ private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
+
+ /** the textposition at the last accepting state */
+ private int zzMarkedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int zzPushbackPos;
+
+ /** the current text position in the buffer */
+ private int zzCurrentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int zzStartRead;
+
+ /**
+ * endRead marks the last character in the buffer, that has been read from
+ * input
+ */
+ private int zzEndRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ int yycolumn;
+
+ /**
+ * zzAtBOL == true <=>the scanner is currently at the beginning of a line
+ */
+ boolean zzAtBOL = true;
+
+ /** zzAtEOF == true <=>the scanner is at the EOF */
+ private boolean zzAtEOF;
+
+ /* user code: */
+
+ /**
+ * Creates a new scanner
+ */
+ public XML10Names() {
+ this.zzReader = null;
+ }
+
+ public boolean isValidXML10Name(String stringToCheck) {
+ boolean result = false;
+ yyreset(new java.io.StringReader(stringToCheck));
+ try {
+ result = isValidXML10Name();
+ } catch (java.io.IOException e) {
+ // should be impossible with strings, but if occurs, just means
+ // "not"
+ result = false;
+ }
+ return result;
+ }
+
+
+
+ /**
+ * Creates a new scanner There is also a java.io.InputStream version of
+ * this constructor.
+ *
+ * @param in
+ * the java.io.Reader to read input from.
+ */
+ public XML10Names(java.io.Reader in) {
+ this.zzReader = in;
+ }
+
+ /**
+ * Creates a new scanner. There is also java.io.Reader version of this
+ * constructor.
+ *
+ * @param in
+ * the java.io.Inputstream to read input from.
+ */
+ public XML10Names(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed
+ * the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char[] zzUnpackCMap(String packed) {
+ char[] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 1226) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do
+ map[j++] = value;
+ while (--count > 0);
+ }
+ return map;
+ }
+
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return <code>false</code>, iff there was new input.
+ *
+ * @exception java.io.IOException
+ * if any I/O-Error occurs
+ */
+ private boolean zzRefill() throws java.io.IOException {
+
+ /* first: make room (if you can) */
+ if (zzStartRead > 0) {
+ System.arraycopy(zzBuffer, zzStartRead, zzBuffer, 0, zzEndRead - zzStartRead);
+
+ /* translate stored positions */
+ zzEndRead -= zzStartRead;
+ zzCurrentPos -= zzStartRead;
+ zzMarkedPos -= zzStartRead;
+ zzPushbackPos -= zzStartRead;
+ zzStartRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (zzCurrentPos >= zzBuffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[zzCurrentPos * 2];
+ System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
+ zzBuffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = zzReader.read(zzBuffer, zzEndRead, zzBuffer.length - zzEndRead);
+
+ if (numRead < 0) {
+ return true;
+ } else {
+ zzEndRead += numRead;
+ return false;
+ }
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ final void yyclose() throws java.io.IOException {
+ zzAtEOF = true; /* indicate end of file */
+ zzEndRead = zzStartRead; /* invalidate buffer */
+
+ if (zzReader != null)
+ zzReader.close();
+ }
+
+
+ /**
+ * Resets the scanner to read from a new input stream. Does not close the
+ * old reader.
+ *
+ * All internal variables are reset, the old input stream <b>cannot </b>
+ * be reused (internal buffer is discarded and lost). Lexical state is set
+ * to <tt>ZZ_INITIAL</tt>.
+ *
+ * @param reader
+ * the new input stream
+ */
+ private final void yyreset(java.io.Reader reader) {
+ zzReader = reader;
+ //zzAtBOL = true;
+ zzAtEOF = false;
+ zzEndRead = zzStartRead = 0;
+ zzCurrentPos = zzMarkedPos = zzPushbackPos = 0;
+ yyline = yychar = yycolumn = 0;
+ zzLexicalState = YYINITIAL;
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ final int yystate() {
+ return zzLexicalState;
+ }
+
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState
+ * the new lexical state
+ */
+ final void yybegin(int newState) {
+ zzLexicalState = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ final String yytext() {
+ return new String(zzBuffer, zzStartRead, zzMarkedPos - zzStartRead);
+ }
+
+
+ /**
+ * Returns the character at position <tt>pos</tt> from the matched text.
+ *
+ * It is equivalent to yytext().charAt(pos), but faster
+ *
+ * @param pos
+ * the position of the character to fetch. A value from 0 to
+ * yylength()-1.
+ *
+ * @return the character at position pos
+ */
+ final char yycharat(int pos) {
+ return zzBuffer[zzStartRead + pos];
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ private final int yylength() {
+ return zzMarkedPos - zzStartRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of yypushback(int)
+ * and a match-all fallback rule) this method will only be called with
+ * things that "Can't Possibly Happen". If this method is called,
+ * something is seriously wrong (e.g. a JFlex bug producing a faulty
+ * scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done in error
+ * fallback rules.
+ *
+ * @param errorCode
+ * the code of the errormessage to display
+ */
+ private void zzScanError(int errorCode) {
+ String message;
+ try {
+ message = ZZ_ERROR_MSG[errorCode];
+ } catch (ArrayIndexOutOfBoundsException e) {
+ message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number
+ * the number of characters to be read again. This number must
+ * not be greater than yylength()!
+ */
+ void yypushback(int number) {
+ if (number > yylength())
+ zzScanError(ZZ_PUSHBACK_2BIG);
+
+ zzMarkedPos -= number;
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched, the end
+ * of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception java.io.IOException
+ * if any I/O-Error occurs
+ */
+ private boolean isValidXML10Name() throws java.io.IOException {
+ int zzInput;
+ int zzAction;
+
+ // cached fields:
+ int zzCurrentPosL;
+ int zzMarkedPosL;
+ int zzEndReadL = zzEndRead;
+ char[] zzBufferL = zzBuffer;
+ char[] zzCMapL = ZZ_CMAP;
+
+ int[] zzTransL = ZZ_TRANS;
+ int[] zzRowMapL = ZZ_ROWMAP;
+ int[] zzAttrL = ZZ_ATTRIBUTE;
+
+ while (true) {
+ zzMarkedPosL = zzMarkedPos;
+
+ zzAction = -1;
+
+ zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+ zzState = zzLexicalState;
+
+
+ zzForAction : {
+ while (true) {
+
+ if (zzCurrentPosL < zzEndReadL)
+ zzInput = zzBufferL[zzCurrentPosL++];
+ else if (zzAtEOF) {
+ zzInput = YYEOF;
+ break zzForAction;
+ } else {
+ // store back cached positions
+ zzCurrentPos = zzCurrentPosL;
+ zzMarkedPos = zzMarkedPosL;
+ boolean eof = zzRefill();
+ // get translated positions and possibly new buffer
+ zzCurrentPosL = zzCurrentPos;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ zzEndReadL = zzEndRead;
+ if (eof) {
+ zzInput = YYEOF;
+ break zzForAction;
+ } else {
+ zzInput = zzBufferL[zzCurrentPosL++];
+ }
+ }
+ int zzNext = zzTransL[zzRowMapL[zzState] + zzCMapL[zzInput]];
+ if (zzNext == -1)
+ break zzForAction;
+ zzState = zzNext;
+
+ int zzAttributes = zzAttrL[zzState];
+ if ((zzAttributes & 1) == 1) {
+ zzAction = zzState;
+ zzMarkedPosL = zzCurrentPosL;
+ if ((zzAttributes & 8) == 8)
+ break zzForAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ zzMarkedPos = zzMarkedPosL;
+
+ switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 1 : {
+ return false;
+ }
+ case 3 :
+ break;
+ case 2 : {
+ return true;
+ }
+ case 4 :
+ break;
+ default :
+ if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+ zzAtEOF = true;
+ {
+ {
+ return false;
+ }
+ }
+ } else {
+ zzScanError(ZZ_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java
new file mode 100644
index 0000000000..5c622ab3c0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+/**
+ * @deprecated - use org.eclipse.wst.xml.core.parser.XMLRegionContext
+ */
+public interface XMLRegionContexts extends XMLRegionContext {
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java
new file mode 100644
index 0000000000..63711818d9
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java
@@ -0,0 +1,595 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.wst.sse.core.document.DocumentReader;
+import org.eclipse.wst.sse.core.internal.text.CharSequenceReader;
+import org.eclipse.wst.sse.core.internal.text.IRegionComparible;
+import org.eclipse.wst.sse.core.parser.BlockMarker;
+import org.eclipse.wst.sse.core.parser.BlockTagParser;
+import org.eclipse.wst.sse.core.parser.BlockTokenizer;
+import org.eclipse.wst.sse.core.parser.RegionParser;
+import org.eclipse.wst.sse.core.parser.StructuredDocumentRegionHandler;
+import org.eclipse.wst.sse.core.parser.StructuredDocumentRegionParser;
+import org.eclipse.wst.sse.core.parser.StructuredDocumentRegionParserExtension;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.sse.core.text.ITextRegionList;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.xml.core.Logger;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+/**
+ * Takes input from the HTMLTokenizer and creates a tag list
+ */
+
+public class XMLSourceParser implements RegionParser, BlockTagParser, StructuredDocumentRegionParser, IRegionComparible, StructuredDocumentRegionParserExtension {
+ // made public to aid access from inner classes in hierarchy.
+ // TODO: in future, figure out how to solve without exposing data.
+ public CharSequence fCharSequenceSource = null;
+ private IDocument fDocumentInput;
+ protected int fOffset = 0;
+ // DMW: 2/12/03. Removed some state data, since not really needed,
+ // and since it added a lot to overhead (since so many regions are
+ // created.
+ // protected IStructuredDocumentRegion fCurrentNode = null;
+ // protected IStructuredDocumentRegion fNodes = null;
+ // protected List fRegions = null;
+ // protected Object fInput = null;
+ protected String fStringInput = null;
+ protected List fStructuredDocumentRegionHandlers;
+
+ protected BlockTokenizer fTokenizer = null;
+ protected long startTime;
+ protected long stopTime;
+
+ /**
+ * HTMLSourceParser constructor comment.
+ */
+ public XMLSourceParser() {
+ super();
+ fStructuredDocumentRegionHandlers = new ArrayList();
+ }
+
+ /**
+ * This is a simple utility to count nodes. Used only for debug
+ * statements.
+ */
+ protected int _countNodes(IStructuredDocumentRegion nodes) {
+ int result = 0;
+ IStructuredDocumentRegion countNode = nodes;
+ while (countNode != null) {
+ result++;
+ countNode = countNode.getNext();
+ }
+ return result;
+ }
+
+ public void addBlockMarker(BlockMarker marker) {
+ getTokenizer().addBlockMarker(marker);
+ }
+
+ public void addStructuredDocumentRegionHandler(StructuredDocumentRegionHandler handler) {
+ if (fStructuredDocumentRegionHandlers == null)
+ fStructuredDocumentRegionHandlers = new ArrayList();
+ fStructuredDocumentRegionHandlers.add(handler);
+ }
+
+ public void beginBlockScan(String newTagName) {
+ getTokenizer().beginBlockTagScan(newTagName);
+ }
+
+ /**
+ * @return IStructuredDocumentRegion
+ */
+ protected IStructuredDocumentRegion createStructuredDocumentRegion(String type) {
+ IStructuredDocumentRegion newNode = null;
+ if (type == XMLRegionContext.BLOCK_TEXT)
+ newNode = XMLStructuredRegionFactory.createRegion(XMLStructuredRegionFactory.XML_BLOCK);
+ else
+ newNode = XMLStructuredRegionFactory.createRegion(XMLStructuredRegionFactory.XML);
+ return newNode;
+ }
+
+ protected void fireNodeParsed(IStructuredDocumentRegion fCurrentNode) {
+ if (fCurrentNode != null && fStructuredDocumentRegionHandlers != null) {
+ for (int i = 0; i < fStructuredDocumentRegionHandlers.size(); i++)
+ ((StructuredDocumentRegionHandler) fStructuredDocumentRegionHandlers.get(i)).nodeParsed(fCurrentNode);
+ }
+ }
+
+ public BlockMarker getBlockMarker(String tagName) {
+ List markers = getTokenizer().getBlockMarkers();
+ for (int i = 0; i < markers.size(); i++) {
+ BlockMarker marker = (BlockMarker) markers.get(i);
+ if (marker.isCaseSensitive()) {
+ if (marker.getTagName().equals(tagName))
+ return marker;
+ } else {
+ if (marker.getTagName().equalsIgnoreCase(tagName))
+ return marker;
+ }
+ }
+ return null;
+ }
+
+ public List getBlockMarkers() {
+ return getTokenizer().getBlockMarkers();
+ }
+
+ /**
+ * @return IStructuredDocumentRegion
+ */
+ public IStructuredDocumentRegion getDocumentRegions() {
+ IStructuredDocumentRegion headnode = null;
+ if (headnode == null) {
+ if (Debug.perfTest) {
+ startTime = System.currentTimeMillis();
+ }
+ headnode = parseNodes();
+ if (Debug.perfTest) {
+ stopTime = System.currentTimeMillis();
+ System.out.println(" -- creating nodes of IStructuredDocument -- "); //$NON-NLS-1$
+ System.out.println(" Time parse and init all regions: " + (stopTime - startTime) + " (msecs)"); //$NON-NLS-2$//$NON-NLS-1$
+ //System.out.println(" for " + fRegions.size() + "
+ // Regions");//$NON-NLS-2$//$NON-NLS-1$
+ System.out.println(" and " + _countNodes(headnode) + " Nodes"); //$NON-NLS-2$//$NON-NLS-1$
+ }
+ }
+ return headnode;
+ }
+
+ protected ITextRegion getNextRegion() {
+ ITextRegion region = null;
+ try {
+ region = getTokenizer().getNextToken();
+ // DMW: 2/12/03 Removed state
+ // if (region != null) {
+ // fRegions.add(region);
+ // }
+ return region;
+ } catch (StackOverflowError e) {
+ Logger.logException(getClass().getName() + ": input could not be parsed correctly at position " + getTokenizer().getOffset(), e); //$NON-NLS-1$
+ throw e;
+ } catch (Exception e) {
+ Logger.logException(getClass().getName() + ": input could not be parsed correctly at position " + getTokenizer().getOffset() + " (" + e.getLocalizedMessage() + ")", e); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Return the full list of known regions. Typically getNodes should be
+ * used instead of this method.
+ */
+ public List getRegions() {
+ IStructuredDocumentRegion headNode = null;
+ if (!getTokenizer().isEOF()) {
+ headNode = getDocumentRegions();
+ // throw new IllegalStateException("parsing has not finished");
+ }
+ // for memory recovery, we assume if someone
+ // requests all regions, we can reset our big
+ // memory consuming objects
+ // but the new "getRegions" method is then more expensive.
+ // I don't think its used much, though.
+ List localRegionsList = getRegions(headNode);
+ primReset();
+ return localRegionsList;
+ }
+
+ /**
+ * Method getRegions.
+ *
+ * @param headNode
+ * @return List
+ */
+ protected List getRegions(IStructuredDocumentRegion headNode) {
+ List allRegions = new ArrayList();
+ IStructuredDocumentRegion currentNode = headNode;
+ while (currentNode != null) {
+ ITextRegionList nodeRegions = currentNode.getRegions();
+ for (int i = 0; i < nodeRegions.size(); i++) {
+ allRegions.add(nodeRegions.get(i));
+ }
+ currentNode = currentNode.getNext();
+ }
+ return allRegions;
+ }
+
+ /**
+ *
+ * @return java.util.List
+ */
+ public List getStructuredDocumentRegionHandlers() {
+ if (fStructuredDocumentRegionHandlers == null) {
+ fStructuredDocumentRegionHandlers = new ArrayList(0);
+ }
+ return fStructuredDocumentRegionHandlers;
+ }
+
+ /**
+ * Returns text from the current input. Text is only valid before
+ * getNodes() has been called and only when a raw String or DocumentReader
+ * is given as the input.
+ */
+ public String getText(int offset, int length) {
+ String text = null;
+ if (fCharSequenceSource != null) {
+ int start = fOffset + offset;
+ int end = start + length;
+ text = fCharSequenceSource.subSequence(start, end).toString();
+ } else if (fDocumentInput != null) {
+ try {
+ text = fDocumentInput.get(offset, length);
+ } catch (BadLocationException e) {
+ text = "";
+ }
+ } else {
+ if (fStringInput == null || fStringInput.length() == 0 || offset + length > fStringInput.length() || offset < 0) {
+ text = ""; //$NON-NLS-1$
+ } else {
+ // offset is entirely valid during parsing as the parse
+ // numbers haven't been adjusted.
+ text = fStringInput.substring(offset, offset + length);
+ }
+ }
+ return text;
+ }
+
+ protected BlockTokenizer getTokenizer() {
+ if (fTokenizer == null) {
+ fTokenizer = new XMLTokenizer();
+ }
+ return fTokenizer;
+ }
+
+ /**
+ * @see com.ibm.sed.parser.RegionParser#newInstance()
+ */
+ public RegionParser newInstance() {
+ XMLSourceParser newInstance = new XMLSourceParser();
+ newInstance.setTokenizer(getTokenizer().newInstance());
+ return newInstance;
+ }
+
+ protected IStructuredDocumentRegion parseNodes() {
+ // regions are initially reported as complete offsets within the
+ // scanned input
+ // they are adjusted here to be indexes from the currentNode's start
+ // offset
+ IStructuredDocumentRegion headNode = null;
+ IStructuredDocumentRegion lastNode = null;
+ ITextRegion region = null;
+ IStructuredDocumentRegion currentNode = null;
+ String type = null;
+
+ while ((region = getNextRegion()) != null) {
+ type = region.getType();
+ // these types (might) demand a IStructuredDocumentRegion for each
+ // of them
+ if (type == XMLRegionContext.BLOCK_TEXT) {
+ if (currentNode != null && currentNode.getLastRegion().getType() == XMLRegionContext.BLOCK_TEXT) {
+ // multiple block texts indicated embedded containers; no
+ // new IStructuredDocumentRegion
+ currentNode.addRegion(region);
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ region.adjustStart(-currentNode.getStart());
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(currentNode);
+ } else {
+ // not continuing a IStructuredDocumentRegion
+ if (currentNode != null) {
+ // ensure that any existing node is at least
+ // terminated
+ if (!currentNode.isEnded()) {
+ currentNode.setLength(region.getStart() - currentNode.getStart());
+ // fCurrentNode.setTextLength(region.getStart() -
+ // fCurrentNode.getStart());
+ }
+ lastNode = currentNode;
+ }
+ fireNodeParsed(currentNode);
+ currentNode = createStructuredDocumentRegion(type);
+ if (lastNode != null) {
+ lastNode.setNext(currentNode);
+ }
+ currentNode.setPrevious(lastNode);
+ currentNode.setStart(region.getStart());
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ currentNode.setEnded(true);
+ region.adjustStart(-currentNode.getStart());
+ currentNode.addRegion(region);
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(currentNode);
+ }
+ }
+ // the following contexts OPEN new StructuredDocumentRegions
+ else if ((currentNode != null && currentNode.isEnded()) || (type == XMLRegionContext.XML_CONTENT) || (type == XMLRegionContext.XML_CHAR_REFERENCE) || (type == XMLRegionContext.XML_ENTITY_REFERENCE) || (type == XMLRegionContext.XML_PI_OPEN) || (type == XMLRegionContext.XML_TAG_OPEN) || (type == XMLRegionContext.XML_END_TAG_OPEN) || (type == XMLRegionContext.XML_COMMENT_OPEN) || (type == XMLRegionContext.XML_CDATA_OPEN) || (type == XMLRegionContext.XML_DECLARATION_OPEN)) {
+ if (currentNode != null) {
+ // ensure that any existing node is at least terminated
+ if (!currentNode.isEnded()) {
+ currentNode.setLength(region.getStart() - currentNode.getStart());
+ // fCurrentNode.setTextLength(region.getStart() -
+ // fCurrentNode.getStart());
+ }
+ lastNode = currentNode;
+ }
+ fireNodeParsed(currentNode);
+ currentNode = createStructuredDocumentRegion(type);
+ if (lastNode != null) {
+ lastNode.setNext(currentNode);
+ }
+ currentNode.setPrevious(lastNode);
+ currentNode.setStart(region.getStart());
+ currentNode.addRegion(region);
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ region.adjustStart(-currentNode.getStart());
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(currentNode);
+ }
+ // the following contexts neither open nor close
+ // StructuredDocumentRegions; just add to them
+ else if ((type == XMLRegionContext.XML_TAG_NAME) || (type == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) || (type == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) || (type == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) || (type == XMLRegionContext.XML_COMMENT_TEXT) || (type == XMLRegionContext.XML_PI_CONTENT) || (type == XMLRegionContext.XML_DOCTYPE_INTERNAL_SUBSET)) {
+ currentNode.addRegion(region);
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ region.adjustStart(-currentNode.getStart());
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(currentNode);
+ }
+ // the following contexts close off StructuredDocumentRegions
+ // cleanly
+ else if ((type == XMLRegionContext.XML_PI_CLOSE) || (type == XMLRegionContext.XML_TAG_CLOSE) || (type == XMLRegionContext.XML_EMPTY_TAG_CLOSE) || (type == XMLRegionContext.XML_COMMENT_CLOSE) || (type == XMLRegionContext.XML_DECLARATION_CLOSE) || (type == XMLRegionContext.XML_CDATA_CLOSE)) {
+ currentNode.setEnded(true);
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ currentNode.addRegion(region);
+ region.adjustStart(-currentNode.getStart());
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(currentNode);
+ }
+ // this is extremely rare, but valid
+ else if (type == XMLRegionContext.WHITE_SPACE) {
+ ITextRegion lastRegion = currentNode.getLastRegion();
+ // pack the embedded container with this region
+ if (lastRegion instanceof ITextRegionContainer) {
+ ITextRegionContainer container = (ITextRegionContainer) lastRegion;
+ container.getRegions().add(region);
+ // containers must have parent set ...
+ // setting for EACH subregion is redundent, but not sure
+ // where else to do, so will do here for now.
+ container.setParent(currentNode);
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(container);
+ region.adjustStart(container.getLength() - region.getStart());
+ }
+ currentNode.getLastRegion().adjustLengthWith(region.getLength());
+ currentNode.adjustLengthWith(region.getLength());
+ } else if (type == XMLRegionContext.UNDEFINED && currentNode != null) {
+ // skip on a very-first region situation as the default
+ // behavior is good enough
+ // combine with previous if also undefined
+ if (currentNode.getLastRegion() != null && currentNode.getLastRegion().getType() == XMLRegionContext.UNDEFINED) {
+ currentNode.getLastRegion().adjustLengthWith(region.getLength());
+ currentNode.adjustLengthWith(region.getLength());
+ }
+ // previous wasn't undefined
+ else {
+ currentNode.addRegion(region);
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ region.adjustStart(-currentNode.getStart());
+ }
+ } else {
+ // if an unknown type is the first region in the document,
+ // ensure that a node exists
+ if (currentNode == null) {
+ currentNode = createStructuredDocumentRegion(type);
+ currentNode.setStart(region.getStart());
+ }
+ currentNode.addRegion(region);
+ currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart());
+ region.adjustStart(-currentNode.getStart());
+ // DW 4/16/2003 regions no longer have parents
+ //region.setParent(currentNode);
+ if (Debug.debugTokenizer)
+ System.out.println(getClass().getName() + " found region of not specifically handled type " + region.getType() + " @ " + region.getStart() + "[" + region.getLength() + "]"); //$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
+ //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
+ }
+
+ // these regions also get their own node, so close them cleanly
+ // NOTE: these regions have new StructuredDocumentRegions created
+ // for them above; it may
+ // be more readable if that is handled here as well, but the
+ // current layout
+ // ensures that they open StructuredDocumentRegions the same way
+ if ((type == XMLRegionContext.XML_CONTENT) || (type == XMLRegionContext.XML_CHAR_REFERENCE) || (type == XMLRegionContext.XML_ENTITY_REFERENCE)) {
+ currentNode.setEnded(true);
+ }
+ if (headNode == null && currentNode != null) {
+ headNode = currentNode;
+ }
+ }
+ if (currentNode != null) {
+ fireNodeParsed(currentNode);
+ currentNode.setPrevious(lastNode);
+ }
+ //fStringInput = null;
+ primReset();
+ return headNode;
+ }
+
+ protected void primReset() {
+ //fNodes = null;
+ //fRegions = null;
+ //fInput = null;
+ fStringInput = null;
+ fCharSequenceSource = null;
+ fDocumentInput = null;
+ fOffset = 0;
+ //fCurrentNode = null;
+ // DMW: also reset tokenizer so it doesn't hold on
+ // to large arrays
+ getTokenizer().reset(new char[0]);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.internal.text.IRegionComparible#regionMatches(int,
+ * int, java.lang.String)
+ */
+ public boolean regionMatches(int offset, int length, String stringToCompare) {
+ // by definition
+ if (stringToCompare == null)
+ return false;
+
+ boolean result = false;
+ if (fCharSequenceSource != null && fCharSequenceSource instanceof IRegionComparible) {
+ result = ((IRegionComparible) fCharSequenceSource).regionMatches(offset, length, stringToCompare);
+ } else {
+ // old fashioned ways
+ String test = null;
+ if (fCharSequenceSource != null) {
+ test = fCharSequenceSource.subSequence(offset, offset + length).toString();
+ } else if (fStringInput != null) {
+ test = fStringInput.substring(offset, offset + length);
+ }
+ result = stringToCompare.equals(test);
+ }
+ return result;
+ }
+
+ public boolean regionMatchesIgnoreCase(int offset, int length, String stringToCompare) {
+ // by definition
+ if (stringToCompare == null)
+ return false;
+
+ boolean result = false;
+ if (fCharSequenceSource != null && fCharSequenceSource instanceof IRegionComparible) {
+ result = ((IRegionComparible) fCharSequenceSource).regionMatchesIgnoreCase(offset, length, stringToCompare);
+ } else {
+ // old fashioned ways
+ String test = null;
+ if (fCharSequenceSource != null) {
+ test = fCharSequenceSource.subSequence(offset, offset + length).toString();
+ } else if (fStringInput != null) {
+ test = fStringInput.substring(offset, offset + length);
+ }
+ result = stringToCompare.equalsIgnoreCase(test);
+ }
+ return result;
+ }
+
+ public void removeBlockMarker(BlockMarker marker) {
+ getTokenizer().removeBlockMarker(marker);
+ }
+
+ public void removeBlockMarker(String tagName) {
+ getTokenizer().removeBlockMarker(tagName);
+ }
+
+ public void removeStructuredDocumentRegionHandler(StructuredDocumentRegionHandler handler) {
+ if (fStructuredDocumentRegionHandlers == null)
+ return;
+ if (fStructuredDocumentRegionHandlers.contains(handler))
+ fStructuredDocumentRegionHandlers.remove(handler);
+ }
+
+ /**
+ * Resets the input.
+ */
+ public void reset(java.io.FileInputStream instream) {
+ primReset();
+ //fInput = instream;
+ getTokenizer().reset(instream);
+ }
+
+ /**
+ * Resets the input.
+ */
+ public void reset(java.io.Reader reader) {
+ reset(reader, 0);
+ }
+
+ /**
+ * Resets the input.
+ */
+ public void reset(java.io.Reader reader, int position) {
+ primReset();
+ fOffset = position;
+ getTokenizer().reset(reader, position);
+ if (reader instanceof DocumentReader) {
+ IDocument doc = ((DocumentReader) reader).getDocument();
+ if (doc instanceof CharSequence) {
+ fCharSequenceSource = (CharSequence) doc;
+ } else {
+ // old fashioned IDocument
+ fDocumentInput = ((DocumentReader) reader).getDocument();
+ }
+
+ } else if (reader instanceof CharSequenceReader) {
+ fCharSequenceSource = ((CharSequenceReader) reader).getOriginalSource();
+ }
+ }
+
+ /**
+ * Resets the input. Use this version to allow text to be retrieved
+ * <em>during</em> parsing, such as by the
+ * StructuredDocumentRegionHandler.
+ */
+ public void reset(String sourceString) {
+ reset(new StringReader(sourceString));
+ fStringInput = sourceString;
+ }
+
+ /**
+ * Resets the input. Use this version to allow text to be retrieved
+ * <em>during</em> parsing, such as by the
+ * StructuredDocumentRegionHandler.
+ */
+ public void reset(String sourceString, int position) {
+ StringReader reader = new StringReader(sourceString);
+ reset(reader, position);
+ fStringInput = sourceString;
+ }
+
+ public void resetHandlers() {
+ if (fStructuredDocumentRegionHandlers != null) {
+ int size = fStructuredDocumentRegionHandlers.size();
+ for (int i = 0; i < size; i++)
+ ((StructuredDocumentRegionHandler) fStructuredDocumentRegionHandlers.get(i)).resetNodes();
+ }
+ }
+
+ /**
+ *
+ * @param List
+ */
+ public void setStructuredDocumentRegionHandlers(List newStructuredDocumentRegionHandlers) {
+ fStructuredDocumentRegionHandlers = newStructuredDocumentRegionHandlers;
+ }
+
+ protected void setTokenizer(BlockTokenizer newTokenizer) {
+ // DMW: changed from private to protected, so subclass could use in
+ // creation of 'newInstance'.
+ fTokenizer = newTokenizer;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java
new file mode 100644
index 0000000000..518d4f63c6
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+import org.eclipse.wst.sse.core.internal.text.StructuredDocumentReParser;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.IStructuredTextReParser;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class XMLStructuredDocumentReParser extends StructuredDocumentReParser {
+
+ public XMLStructuredDocumentReParser() {
+ super();
+ }
+
+ protected IStructuredDocumentRegion findDirtyEnd(int end) {
+ // Caution: here's one place we have to cast
+ IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(end);
+ // if not well formed, get one past, if there is something there
+ if ((result != null) && (!result.isEnded())) {
+ if (result.getNext() != null) {
+ result = result.getNext();
+ }
+ }
+ // also, get one past if exactly equal to the end (this was needed
+ // as a simple fix to when a whole exact region is deleted.
+ // there's probably a better way.
+ if ((result != null) && (end == result.getEnd())) {
+ if (result.getNext() != null) {
+ result = result.getNext();
+ }
+ }
+
+ // 12/6/2001 - Since we've changed the parser/scanner to allow a lone
+ // '<' without
+ // always interpretting it as start of a tag name, we need to be a
+ // little fancier, in order
+ // to "skip" over any plain 'ol content between the lone '<' and any
+ // potential meating
+ // regions past plain 'ol content.
+ if (isLoneOpenFollowedByContent(result) && (result.getNext() != null)) {
+ result = result.getNext();
+ }
+
+ if (result != null)
+ fStructuredDocument.setCachedDocumentRegion(result);
+ dirtyEnd = result;
+
+ return dirtyEnd;
+ }
+
+ protected void findDirtyStart(int start) {
+ IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(start);
+ // heuristic: if the postion is exactly equal to the start, then
+ // go back one more, if it exists. This prevents problems with
+ // insertions
+ // of text that should be merged with the previous node instead of
+ // simply hung
+ // off of it as a separate node (ex.: XML content inserted right
+ // before an open
+ // bracket should become part of the previous content node)
+ if (result != null) {
+ IStructuredDocumentRegion previous = result.getPrevious();
+ if ((previous != null) && ((!(previous.isEnded())) || (start == result.getStart()))) {
+ result = previous;
+ }
+ // If we are now at the end of a "tag dependent" content area (or
+ // JSP area)
+ // then we need to back up all the way to the beginning of that.
+ IStructuredDocumentRegion potential = result;
+ while (isPartOfBlockRegion(potential)) {
+ potential = potential.getPrevious();
+ }
+ if (potential != null) {
+ result = potential;
+ fStructuredDocument.setCachedDocumentRegion(result);
+ }
+ }
+ dirtyStart = result;
+ }
+
+ /**
+ * The rule is, that is we are content, preceded by lone <, then we need
+ * to advance one more for dirty end.
+ */
+ protected boolean isLoneOpenFollowedByContent(IStructuredDocumentRegion flatNode) {
+ boolean result = false;
+ String type = flatNode.getType();
+ if (type == XMLRegionContext.XML_CONTENT) {
+ IStructuredDocumentRegion previous = flatNode.getPrevious();
+ String previousType = null;
+ if (previous != null) {
+ previousType = previous.getType();
+ }
+ if (previousType != null) {
+ result = (previousType == XMLRegionContext.XML_TAG_OPEN);
+ }
+ }
+ return result;
+ }
+
+ protected boolean isPartOfBlockRegion(IStructuredDocumentRegion flatNode) {
+ boolean result = false;
+ String type = flatNode.getType();
+ result = (type == XMLRegionContext.BLOCK_TEXT || type == XMLJSPRegionContexts.JSP_CONTENT);
+ return result;
+ }
+
+ public IStructuredTextReParser newInstance() {
+ return new XMLStructuredDocumentReParser();
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java
new file mode 100644
index 0000000000..0411d664e2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.internal.text.XMLStructuredDocumentRegion;
+
+
+/**
+ * A simple class to generate instances of StructuredRegions.
+ */
+public class XMLStructuredRegionFactory {
+ public final static int JSP_DIRECTIVE = 1003;
+ public final static int XML = 1001;
+ public final static int XML_BLOCK = 1002;
+
+ public static IStructuredDocumentRegion createRegion(int type) {
+ IStructuredDocumentRegion instance = null;
+ switch (type) {
+ case XML :
+ instance = new XMLStructuredDocumentRegion();
+ break;
+ case XML_BLOCK :
+ instance = new BlockStructuredDocumentRegion();
+ break;
+ default :
+ throw new IllegalArgumentException("AbstractRegion::createRegion. Invalid type."); //$NON-NLS-1$
+ }
+ return instance;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java
new file mode 100644
index 0000000000..5f1101f1f8
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java
@@ -0,0 +1,1699 @@
+/*******************************************************************************
+ * Copyright (c) 2004 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 Corporation - initial API and implementation
+ *******************************************************************************/
+/* The following code was generated by JFlex 1.2.2 on 9/23/04 1:31 AM */
+
+/*nlsXXX*/
+package org.eclipse.wst.xml.core.internal.parser;
+
+import java.io.CharArrayReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.wst.sse.core.parser.BlockMarker;
+import org.eclipse.wst.sse.core.parser.BlockTokenizer;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.StringUtils;
+import org.eclipse.wst.xml.core.Logger;
+import org.eclipse.wst.xml.core.internal.parser.regions.XMLParserRegionFactory;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+
+/**
+ * This class is a scanner generated by <a
+ * href="http://www.informatik.tu-muenchen.de/~kleing/jflex/">JFlex </a> 1.2.2
+ * on 9/23/04 1:31 AM from the specification file
+ * <tt>file:/D:/eclipse.rad/workspace.rad/org.eclipse.wst.sse.core/DevTimeSupport/SedModel/HTMLTokenizer/devel/XMLTokenizer.jflex</tt>
+ */
+public class XMLTokenizer implements BlockTokenizer, XMLRegionContext {
+
+ /** this character denotes the end of file */
+ final public static int YYEOF = -1;
+
+ /** lexical states */
+ final public static int ST_XML_DOCTYPE_EXTERNAL_ID = 23;
+ final public static int ST_XML_ELEMENT_DECLARATION_CONTENT = 27;
+ final public static int ST_DHTML_ATTRIBUTE_NAME = 12;
+ final public static int ST_XML_PI_TAG_CLOSE = 11;
+ final public static int ST_XML_DECLARATION_CLOSE = 21;
+ final public static int ST_XML_PI_ATTRIBUTE_VALUE = 10;
+ final public static int ST_DHTML_EQUALS = 13;
+ final public static int ST_XML_TAG_NAME = 16;
+ final public static int ST_XML_ATTRIBUTE_VALUE = 19;
+ final public static int ST_DHTML_ATTRIBUTE_VALUE = 14;
+ final public static int ST_XML_DOCTYPE_ID_SYSTEM = 25;
+ final public static int ST_XML_ATTRIBUTE_NAME = 17;
+ final public static int ST_XML_ELEMENT_DECLARATION = 26;
+ final public static int ST_XML_DOCTYPE_DECLARATION = 22;
+ final public static int ST_XML_ATTLIST_DECLARATION = 28;
+ final public static int ST_XML_COMMENT_END = 4;
+ final public static int ST_CDATA_TEXT = 1;
+ final public static int ST_DHTML_TAG_CLOSE = 15;
+ final public static int ST_XML_COMMENT = 3;
+ final public static int ST_PI_CONTENT = 7;
+ final public static int ST_PI_WS = 6;
+ final public static int ST_CDATA_END = 2;
+ final public static int ST_XML_ATTLIST_DECLARATION_CONTENT = 29;
+ final public static int ST_BLOCK_TAG_SCAN = 30;
+ final public static int ST_XML_PI_EQUALS = 9;
+ final public static int ST_XML_DECLARATION = 20;
+ final public static int YYINITIAL = 0;
+ final public static int ST_XML_DOCTYPE_ID_PUBLIC = 24;
+ final public static int ST_XML_EQUALS = 18;
+ final public static int ST_PI = 5;
+ final public static int ST_XML_PI_ATTRIBUTE_NAME = 8;
+
+ /**
+ * Translates characters to character classes
+ */
+ final private static String yycmap_packed = "\11\0\1\5\1\22\2\0\1\14\22\0\1\14\1\21\1\11\1\51" + "\1\16\1\17\1\12\1\13\1\16\1\16\1\16\1\16\1\16\1\7" + "\1\6\1\3\12\15\1\10\1\54\1\1\1\43\1\2\1\4\1\16" + "\1\32\1\55\1\30\1\31\1\35\1\52\1\34\1\34\1\40\1\34" + "\1\34\1\26\1\25\1\42\1\41\1\45\1\34\1\36\1\37\1\33" + "\1\53\2\34\1\23\1\44\1\34\1\27\1\0\1\20\1\0\1\10" + "\1\0\1\47\1\55\1\56\1\50\1\35\1\52\1\34\1\34\1\40" + "\2\34\1\26\1\25\1\42\1\41\1\45\1\34\1\36\1\37\1\46" + "\1\53\1\34\1\34\1\24\1\44\1\34\1\0\1\0\72\0\1\60" + "\10\0\27\57\1\0\37\57\1\0\72\57\2\0\13\57\2\0\10\57" + "\1\0\65\57\1\0\104\57\11\0\44\57\3\0\2\57\4\0\36\57" + "\70\0\131\57\22\0\7\57\16\0\2\60\56\0\106\60\32\0\2\60" + "\44\0\1\57\1\60\3\57\1\0\1\57\1\0\24\57\1\0\54\57" + "\1\0\7\57\3\0\1\57\1\0\1\57\1\0\1\57\1\0\1\57" + "\1\0\22\57\15\0\14\57\1\0\102\57\1\0\14\57\1\0\44\57" + "\1\0\4\60\11\0\65\57\2\0\2\57\2\0\2\57\3\0\34\57" + "\2\0\10\57\2\0\2\57\67\0\46\57\2\0\1\57\7\0\46\57"
+ + "\12\0\21\60\1\0\27\60\1\0\3\60\1\0\1\60\1\0\2\60" + "\1\0\1\60\13\0\33\57\5\0\3\57\56\0\32\57\5\0\1\60" + "\12\57\10\60\15\0\12\60\6\0\1\60\107\57\2\0\5\57\1\0" + "\17\57\1\0\4\57\1\0\1\57\17\60\2\57\2\60\1\0\4\60" + "\2\0\12\60\u0207\0\3\60\1\0\65\57\2\0\1\60\1\57\20\60" + "\3\0\4\60\3\0\12\57\2\60\2\0\12\60\21\0\3\60\1\0" + "\10\57\2\0\2\57\2\0\26\57\1\0\7\57\1\0\1\57\3\0" + "\4\57\2\0\1\60\1\0\7\60\2\0\2\60\2\0\3\60\11\0" + "\1\60\4\0\2\57\1\0\3\57\2\60\2\0\12\60\2\57\20\0" + "\1\60\2\0\6\57\4\0\2\57\2\0\26\57\1\0\7\57\1\0" + "\2\57\1\0\2\57\1\0\2\57\2\0\1\60\1\0\5\60\4\0" + "\2\60\2\0\3\60\13\0\4\57\1\0\1\57\7\0\12\60\2\60" + "\3\57\14\0\3\60\1\0\7\57\1\0\1\57\1\0\3\57\1\0" + "\26\57\1\0\7\57\1\0\2\57\1\0\5\57\2\0\1\60\1\57" + "\10\60\1\0\3\60\1\0\3\60\22\0\1\57\5\0\12\60\21\0" + "\3\60\1\0\10\57\2\0\2\57\2\0\26\57\1\0\7\57\1\0" + "\2\57\2\0\4\57\2\0\1\60\1\57\6\60\3\0\2\60\2\0" + "\3\60\10\0\2\60\4\0\2\57\1\0\3\57\4\0\12\60\22\0"
+ + "\2\60\1\0\6\57\3\0\3\57\1\0\4\57\3\0\2\57\1\0" + "\1\57\1\0\2\57\3\0\2\57\3\0\3\57\3\0\10\57\1\0" + "\3\57\4\0\5\60\3\0\3\60\1\0\4\60\11\0\1\60\17\0" + "\11\60\21\0\3\60\1\0\10\57\1\0\3\57\1\0\27\57\1\0" + "\12\57\1\0\5\57\4\0\7\60\1\0\3\60\1\0\4\60\7\0" + "\2\60\11\0\2\57\4\0\12\60\22\0\2\60\1\0\10\57\1\0" + "\3\57\1\0\27\57\1\0\12\57\1\0\5\57\4\0\7\60\1\0" + "\3\60\1\0\4\60\7\0\2\60\7\0\1\57\1\0\2\57\4\0" + "\12\60\22\0\2\60\1\0\10\57\1\0\3\57\1\0\27\57\1\0" + "\20\57\4\0\6\60\2\0\3\60\1\0\4\60\11\0\1\60\10\0" + "\2\57\4\0\12\60\221\0\56\57\1\0\1\57\1\60\2\57\7\60" + "\5\0\6\57\1\60\10\60\1\0\12\60\47\0\2\57\1\0\1\57" + "\2\0\2\57\1\0\1\57\2\0\1\57\6\0\4\57\1\0\7\57" + "\1\0\3\57\1\0\1\57\1\0\1\57\2\0\2\57\1\0\2\57" + "\1\0\1\57\1\60\2\57\6\60\1\0\2\60\1\57\2\0\5\57" + "\1\0\1\60\1\0\6\60\2\0\12\60\76\0\2\60\6\0\12\60" + "\13\0\1\60\1\0\1\60\1\0\1\60\4\0\2\60\10\57\1\0" + "\41\57\7\0\24\60\1\0\6\60\4\0\6\60\1\0\1\60\1\0"
+ + "\25\60\3\0\7\60\1\0\1\60\346\0\46\57\12\0\47\57\11\0" + "\1\57\1\0\2\57\1\0\3\57\1\0\1\57\1\0\2\57\1\0" + "\5\57\51\0\1\57\1\0\1\57\1\0\1\57\13\0\1\57\1\0" + "\1\57\1\0\1\57\3\0\2\57\3\0\1\57\5\0\3\57\1\0" + "\1\57\1\0\1\57\1\0\1\57\1\0\1\57\3\0\2\57\3\0" + "\2\57\1\0\1\57\50\0\1\57\11\0\1\57\2\0\1\57\2\0" + "\2\57\7\0\2\57\1\0\1\57\1\0\7\57\50\0\1\57\4\0" + "\1\57\10\0\1\57\u0c06\0\234\57\4\0\132\57\6\0\26\57\2\0" + "\6\57\2\0\46\57\2\0\6\57\2\0\10\57\1\0\1\57\1\0" + "\1\57\1\0\1\57\1\0\37\57\2\0\65\57\1\0\7\57\1\0" + "\1\57\3\0\3\57\1\0\7\57\3\0\4\57\2\0\6\57\4\0" + "\15\57\5\0\3\57\1\0\7\57\323\0\15\60\4\0\1\60\104\0" + "\1\57\3\0\2\57\2\0\1\57\121\0\3\57\u0e82\0\1\60\1\0" + "\1\57\31\0\11\57\6\60\1\0\5\60\13\0\124\57\4\0\2\60" + "\2\0\2\60\2\0\132\57\1\0\3\60\6\0\50\57\u1cd3\0\u51a6\57" + "\u0c5a\0\u2ba4\57\134\0\u0800\0\u1ffe\0\2\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ final private static char[] yycmap = yy_unpack_cmap(yycmap_packed);
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ final private static int yy_rowMap[] = {0, 49, 98, 147, 196, 245, 294, 343, 392, 441, 490, 539, 588, 637, 686, 735, 784, 833, 882, 931, 980, 1029, 1078, 1127, 1176, 1225, 1274, 1323, 1372, 1421, 1470, 1519, 1568, 1617, 1666, 1715, 1764, 1715, 1764, 1813, 1715, 1715, 1764, 1862, 1911, 1960, 2009, 2058, 2107, 2156, 1715, 1764, 2205, 2254, 2303, 1715, 2352, 2352, 2401, 2450, 2499, 2205, 1715, 2548, 2597, 1715, 2646, 2695, 2744, 2793, 2842, 2891, 1715, 2940, 2989, 3038, 3087, 1715, 3136, 3185, 3234, 3283, 3332, 1715, 3381, 3430, 3479, 3528, 3577, 3626, 3675, 3724, 3724, 3773, 3822, 3871, 3920, 3920, 3969, 4018, 4067, 4116, 4116, 4165, 4214, 4263, 4312, 1715, 4361, 4361, 4410, 4459, 4508, 4557, 1715, 1715, 1764, 1715, 1715, 4606, 4655, 4704, 4753, 4802, 4851, 4900, 4949, 1715, 4998, 5047, 1715, 1715, 2352, 5096, 2450, 1715, 5145, 2499, 2548, 2646, 2695, 5194, 2744, 1715, 5243, 2793, 1715, 3136, 5292, 3234, 1715, 5341, 3283, 4606, 5390, 5439, 5488, 3528, 1715, 5537, 5586, 3724, 5635,
+ 3773, 1715, 5684, 5733, 5782, 5782, 5831, 5880, 3871, 3724, 3920, 5929, 3969, 1715, 5978, 4018, 4067, 3920, 4116, 6027, 4165, 1715, 6076, 6125, 6174, 6174, 6223, 6272, 6321, 4361, 6370, 4410, 1715, 6419, 6468, 6517, 6517, 6566, 6615, 6664, 6713, 6762, 6811, 6860, 1715, 6909, 6958, 1715, 1715, 1715, 2009, 7007, 7056, 7105, 7154, 7203, 7252, 5684, 7301, 7301, 6076, 7350, 7350, 7399, 6419, 7448, 7448, 7497, 1715, 7546, 7595, 1715, 7644, 7693, 7742, 7791, 7840, 7889, 7938, 5831, 6223, 7987, 6566, 8036, 8085, 8134, 8183, 8232, 8281, 8330, 8379, 8428, 8477, 8526, 2009, 8575, 8624, 8673, 1715, 1715, 8722, 8771, 8820, 1715, 1715, 1715, 8869, 8918, 8967, 9016, 9065, 1715, 4263, 4508};
+
+ /**
+ * The packed transition table of the DFA
+ */
+ final private static String yy_packed = "\1\40\1\41\10\40\1\42\4\40\1\43\41\40\1\44" + "\1\45\57\44\1\46\1\47\16\46\1\50\1\46\1\51" + "\36\46\1\52\1\53\57\52\1\46\1\47\5\46\1\54" + "\12\46\1\51\37\46\1\47\2\46\1\55\1\56\2\46" + "\1\57\3\46\1\56\5\46\1\56\2\60\2\57\1\46" + "\10\57\1\61\2\57\1\46\5\57\1\46\2\57\1\46" + "\3\57\2\46\1\47\2\46\1\55\1\62\6\46\1\62" + "\5\46\1\62\36\46\1\63\1\64\2\63\1\65\15\63" + "\1\51\36\63\1\46\1\47\2\46\1\66\1\56\2\46" + "\1\67\3\46\1\56\5\46\1\56\4\67\1\46\13\67" + "\1\46\5\67\1\46\2\67\1\46\3\67\2\46\1\47" + "\2\46\1\66\1\56\2\46\1\67\3\46\1\56\5\46" + "\1\56\4\67\1\46\13\67\1\70\5\67\1\46\2\67" + "\1\46\3\67\1\46\1\71\1\47\1\46\1\72\1\73" + "\1\56\3\71\1\74\1\71\1\75\1\56\5\71\1\56" + "\36\71\1\46\1\47\2\46\1\76\15\46\1\51\37\46" + "\1\47\1\77\1\100\1\46\1\56\2\46\1\101\3\46" + "\1\56\5\46\1\56\4\101\1\46\13\101\1\46\5\101" + "\1\46\2\101\1\46\3\101\2\46\1\47\1\77\1\100" + "\1\46\1\56\2\46\1\101\3\46\1\56\5\46\1\56"
+ + "\4\101\1\46\13\101\1\102\5\101\1\46\2\101\1\46" + "\3\101\1\46\1\103\1\47\1\77\1\104\1\103\1\56" + "\3\103\1\105\1\103\1\106\1\56\5\103\1\56\36\103" + "\1\46\1\47\3\46\1\56\6\46\1\56\5\46\1\56" + "\36\46\1\107\1\110\1\111\1\112\4\107\1\113\12\107" + "\4\114\1\107\13\114\1\107\5\114\1\107\2\114\1\107" + "\3\114\1\107\1\46\1\110\1\111\1\112\1\46\1\56" + "\2\46\1\115\3\46\1\56\5\46\1\56\4\115\1\46" + "\13\115\1\46\5\115\1\46\2\115\1\46\3\115\2\46" + "\1\110\1\111\1\112\1\46\1\56\2\46\1\115\3\46" + "\1\56\5\46\1\56\4\115\1\46\13\115\1\116\5\115" + "\1\46\2\115\1\46\3\115\1\46\1\117\1\110\1\111" + "\1\120\1\117\1\56\3\117\1\121\1\117\1\122\1\56" + "\5\117\1\56\36\117\1\46\1\123\1\124\2\46\1\56" + "\6\46\1\56\5\46\1\56\6\46\1\125\1\126\2\46" + "\1\127\11\46\1\126\1\125\11\46\1\47\1\124\2\46" + "\1\56\6\46\1\56\5\46\1\56\4\46\1\130\32\46" + "\1\47\1\124\2\46\1\56\2\46\1\131\3\46\1\56" + "\5\46\1\56\4\131\1\130\13\131\1\46\5\131\1\46"
+ + "\2\131\1\46\3\131\2\46\1\47\1\124\2\46\1\56" + "\6\46\1\56\5\46\1\56\4\46\1\130\7\46\1\132" + "\5\46\1\133\13\46\1\134\1\47\1\124\1\135\1\134" + "\1\56\3\134\1\136\1\134\1\137\1\56\5\134\1\56" + "\4\134\1\140\31\134\1\141\1\47\1\124\1\142\1\141" + "\1\56\3\141\1\143\1\141\1\144\1\56\5\141\1\56" + "\4\141\1\145\31\141\1\146\1\47\1\124\1\147\1\146" + "\1\56\3\146\1\150\1\146\1\151\1\56\5\146\1\56" + "\36\146\1\152\1\153\1\154\56\152\1\155\1\47\1\124" + "\1\156\1\155\1\56\3\155\1\157\1\155\1\160\1\56" + "\5\155\1\56\36\155\1\161\1\162\1\163\56\161\1\164" + "\1\165\57\164\1\40\1\0\10\40\1\0\4\40\1\0" + "\41\40\3\0\1\166\1\167\14\0\1\170\44\0\1\171" + "\2\0\1\172\3\0\1\171\5\0\1\171\4\172\1\0" + "\13\172\1\0\5\172\1\173\2\172\1\0\3\172\6\0" + "\1\171\2\0\1\174\3\0\1\171\5\0\1\171\4\174" + "\1\0\13\174\1\0\5\174\1\0\2\174\1\0\3\174" + "\103\0\1\175\57\0\1\176\47\0\1\177\53\0\1\200" + "\63\0\1\56\6\0\1\56\5\0\1\56\44\0\3\57" + "\4\0\1\57\5\0\4\57\1\0\13\57\1\0\5\57"
+ + "\1\0\2\57\1\0\4\57\6\0\3\57\4\0\1\57" + "\5\0\2\57\1\201\1\57\1\0\13\57\1\0\5\57" + "\1\0\2\57\1\0\4\57\6\0\3\57\4\0\1\57" + "\5\0\2\57\1\202\1\57\1\0\13\57\1\0\5\57" + "\1\0\2\57\1\0\4\57\5\0\1\62\6\0\1\62" + "\5\0\1\62\40\0\1\203\60\0\1\204\64\0\3\67" + "\4\0\1\67\5\0\4\67\1\0\13\67\1\0\5\67" + "\1\0\2\67\1\0\4\67\1\71\2\0\1\205\1\71" + "\1\0\3\71\1\0\1\71\2\0\5\71\1\0\37\71" + "\1\0\1\204\1\205\1\71\1\0\3\71\1\0\1\71" + "\2\0\5\71\1\0\36\71\1\74\1\0\1\206\1\207" + "\1\74\1\206\3\74\1\210\1\74\2\206\5\74\1\206" + "\36\74\1\75\1\0\1\211\1\212\1\75\1\211\3\75" + "\1\211\1\75\1\210\1\211\5\75\1\211\36\75\2\0" + "\1\77\1\213\63\0\3\101\4\0\1\101\5\0\4\101" + "\1\0\13\101\1\0\5\101\1\0\2\101\1\0\4\101" + "\1\103\2\0\1\214\1\103\1\0\3\103\1\0\1\103" + "\2\0\5\103\1\0\37\103\1\0\1\77\1\215\1\103" + "\1\0\3\103\1\0\1\103\2\0\5\103\1\0\36\103" + "\1\105\1\0\1\216\1\217\1\105\1\216\3\105\1\220" + "\1\105\2\216\5\105\1\216\36\105\1\106\1\0\1\221"
+ + "\1\222\1\106\1\221\3\106\1\221\1\106\1\220\1\221" + "\5\106\1\221\36\106\1\107\3\0\17\107\4\0\1\107" + "\13\0\1\107\5\0\1\107\2\0\1\107\3\0\1\107" + "\3\0\1\166\15\0\1\170\41\0\1\223\56\0\1\107" + "\3\0\2\107\3\113\4\107\1\113\5\107\4\114\1\107" + "\13\114\1\107\5\114\1\107\2\114\1\107\3\114\1\113" + "\6\0\3\114\4\0\1\114\5\0\4\114\1\0\13\114" + "\1\0\5\114\1\0\2\114\1\0\4\114\6\0\3\115" + "\4\0\1\115\5\0\4\115\1\0\13\115\1\0\5\115" + "\1\0\2\115\1\0\4\115\1\117\2\0\1\224\1\117" + "\1\0\3\117\1\0\1\117\2\0\5\117\1\0\37\117" + "\1\0\1\223\1\224\1\117\1\0\3\117\1\0\1\117" + "\2\0\5\117\1\0\36\117\1\121\1\0\1\225\1\226" + "\1\121\1\225\3\121\1\227\1\121\2\225\5\121\1\225" + "\36\121\1\122\1\0\1\230\1\231\1\122\1\230\3\122" + "\1\230\1\122\1\227\1\230\5\122\1\230\36\122\3\0" + "\1\166\15\0\1\232\100\0\1\233\52\0\1\234\12\0" + "\1\234\40\0\1\235\32\0\20\236\1\237\40\236\6\0" + "\3\131\4\0\1\131\5\0\4\131\1\0\13\131\1\0" + "\5\131\1\0\2\131\1\0\4\131\44\0\1\240\67\0"
+ + "\1\241\5\0\1\134\2\0\1\242\1\134\1\0\3\134" + "\1\0\1\134\2\0\5\134\1\0\36\134\1\136\1\0" + "\1\243\1\244\1\136\1\243\3\136\1\245\1\136\2\243" + "\5\136\1\243\36\136\1\246\1\0\1\247\1\250\1\251" + "\1\247\3\251\1\247\1\246\1\252\1\253\3\251\1\246" + "\1\251\1\253\4\251\1\246\27\251\2\246\1\140\2\236" + "\1\254\1\140\1\236\3\140\1\236\1\140\2\236\3\140" + "\1\255\1\140\1\236\36\140\1\141\2\0\1\256\1\141" + "\1\0\3\141\1\0\1\141\2\0\5\141\1\0\36\141" + "\1\143\2\257\1\260\1\143\1\257\3\143\1\261\1\143" + "\2\257\5\143\1\257\36\143\1\144\2\262\1\263\1\144" + "\1\262\3\144\1\262\1\144\1\261\1\262\5\144\1\262" + "\36\144\1\145\2\236\1\264\1\145\1\236\3\145\1\236" + "\1\145\2\236\3\145\1\265\1\145\1\236\36\145\1\146" + "\2\0\1\266\1\146\1\0\3\146\1\0\1\146\2\0" + "\5\146\1\0\36\146\1\150\1\0\1\267\1\270\1\150" + "\1\267\3\150\1\271\1\150\2\267\5\150\1\267\36\150" + "\1\272\1\0\1\273\1\274\1\275\1\273\3\275\1\273" + "\1\272\1\276\1\277\3\275\1\272\1\275\1\277\4\275"
+ + "\1\272\27\275\2\272\2\152\1\0\60\152\1\0\16\152" + "\1\300\37\152\1\155\2\0\1\301\1\155\1\0\3\155" + "\1\0\1\155\2\0\5\155\1\0\36\155\1\157\1\0" + "\1\302\1\303\1\157\1\302\3\157\1\304\1\157\2\302" + "\5\157\1\302\36\157\1\305\1\0\1\306\1\307\1\310" + "\1\306\3\310\1\306\1\305\1\311\1\312\3\310\1\305" + "\1\310\1\312\4\310\1\305\27\310\2\305\2\161\1\0" + "\60\161\1\0\16\161\1\313\37\161\7\0\1\314\17\0" + "\1\315\36\0\1\171\2\0\1\40\3\0\1\171\5\0" + "\1\171\4\40\1\0\13\40\1\0\5\40\1\0\2\40" + "\1\0\3\40\1\0\1\316\1\0\3\316\1\317\3\172" + "\1\316\1\0\1\316\1\317\1\172\1\316\1\0\2\316" + "\1\317\4\172\1\316\13\172\1\316\5\172\1\316\2\172" + "\1\320\4\172\15\0\1\321\6\0\1\322\34\0\1\316" + "\1\0\3\316\1\317\3\174\1\316\1\0\1\316\1\317" + "\1\174\1\316\1\0\2\316\1\317\4\174\1\316\13\174" + "\1\316\5\174\1\316\2\174\1\323\4\174\27\0\1\315" + "\33\0\1\324\60\0\1\325\64\0\3\57\4\0\1\57" + "\5\0\3\57\1\326\1\0\13\57\1\0\5\57\1\0" + "\2\57\1\0\4\57\6\0\3\57\4\0\1\57\5\0"
+ + "\4\57\1\0\13\57\1\0\1\57\1\327\3\57\1\0" + "\2\57\1\0\4\57\1\206\1\0\7\206\1\210\47\206" + "\1\211\1\0\11\211\1\210\45\211\1\216\1\0\7\216" + "\1\220\47\216\1\221\1\0\11\221\1\220\45\221\1\225" + "\1\0\7\225\1\227\47\225\1\230\1\0\11\230\1\227" + "\45\230\30\0\1\330\25\0\1\330\35\0\1\331\12\0" + "\1\331\47\0\1\332\62\0\1\333\76\0\1\334\3\0" + "\1\243\1\0\7\243\1\245\47\243\1\246\1\0\1\247" + "\1\335\1\246\1\247\3\246\1\247\1\246\1\245\1\247" + "\5\246\1\247\36\246\1\247\1\0\11\247\1\245\45\247" + "\1\246\1\0\1\247\1\335\1\246\1\247\3\246\1\247" + "\1\246\1\336\1\247\5\246\1\247\36\246\13\0\1\337" + "\45\0\1\247\1\0\11\247\1\336\45\247\11\257\1\261" + "\47\257\13\262\1\261\45\262\1\267\1\0\7\267\1\271" + "\47\267\1\272\1\0\1\273\1\340\1\272\1\273\3\272" + "\1\273\1\272\1\271\1\273\5\272\1\273\36\272\1\273" + "\1\0\11\273\1\271\45\273\1\272\1\0\1\273\1\340" + "\1\272\1\273\3\272\1\273\1\272\1\341\1\273\5\272" + "\1\273\36\272\13\0\1\342\45\0\1\273\1\0\11\273"
+ + "\1\341\45\273\2\152\1\0\24\152\1\343\31\152\1\302" + "\1\0\7\302\1\304\47\302\1\305\1\0\1\306\1\344" + "\1\305\1\306\3\305\1\306\1\305\1\304\1\306\5\305" + "\1\306\36\305\1\306\1\0\11\306\1\304\45\306\1\305" + "\1\0\1\306\1\344\1\305\1\306\3\305\1\306\1\305" + "\1\345\1\306\5\305\1\306\36\305\13\0\1\346\45\0" + "\1\306\1\0\11\306\1\345\45\306\2\161\1\0\24\161" + "\1\347\31\161\7\0\1\350\101\0\1\351\30\0\1\316" + "\1\0\10\316\1\0\4\316\1\0\34\316\1\0\5\316" + "\1\0\3\316\1\317\4\316\1\0\1\316\1\317\2\316" + "\1\0\2\316\1\317\31\316\1\352\4\316\15\0\1\321" + "\36\0\1\353\21\0\1\354\12\0\3\354\2\0\1\354" + "\11\0\2\354\1\0\1\354\2\0\2\354\10\0\3\57" + "\4\0\1\57\5\0\4\57\1\0\11\57\1\355\1\57" + "\1\0\5\57\1\0\2\57\1\0\4\57\33\0\1\356" + "\12\0\1\356\40\0\1\357\57\0\1\360\66\0\1\361" + "\12\0\1\361\40\0\1\362\35\0\2\363\1\0\3\363" + "\2\0\1\252\4\363\1\0\6\363\1\0\27\363\5\0" + "\2\364\1\0\3\364\2\0\1\276\4\364\1\0\6\364"
+ + "\1\0\27\364\2\0\2\152\1\0\25\152\1\365\30\152" + "\3\0\2\366\1\0\3\366\2\0\1\311\4\366\1\0" + "\6\366\1\0\27\366\2\0\2\161\1\0\25\161\1\367" + "\30\161\31\0\1\370\103\0\1\352\21\0\1\354\12\0" + "\3\354\2\0\1\354\11\0\2\354\1\0\1\354\1\0" + "\1\353\2\354\10\0\3\57\4\0\1\57\5\0\4\57" + "\1\0\6\57\1\371\4\57\1\0\5\57\1\0\2\57" + "\1\0\4\57\44\0\1\372\54\0\1\373\55\0\1\374" + "\60\0\1\375\63\0\1\376\20\0\2\152\1\0\26\152" + "\1\377\27\152\2\161\1\0\26\161\1\u0100\27\161\32\0" + "\1\u0101\34\0\3\57\4\0\1\57\5\0\4\57\1\0" + "\3\57\1\u0102\7\57\1\0\2\57\1\u0102\2\57\1\0" + "\2\57\1\0\4\57\45\0\1\u0103\52\0\1\u0104\63\0" + "\1\u0105\43\0\1\u0106\63\0\1\u0107\25\0\1\u0107\2\0" + "\2\152\1\0\27\152\1\u0108\26\152\2\161\1\0\27\161" + "\1\u0109\26\161\33\0\1\u010a\62\0\1\u010b\56\0\1\u010c" + "\12\0\1\u010c\45\0\1\u010d\12\0\1\u010d\12\0\2\152" + "\1\0\30\152\1\u010e\25\152\2\161\1\0\30\161\1\u010f" + "\25\161\32\0\1\u0110\26\0\2\152\1\0\27\152\1\u0111"
+ + "\26\152\2\161\1\0\27\161\1\u0112\26\161\27\0\1\u0113" + "\31\0\2\152\1\0\24\152\1\u0114\31\152\2\161\1\0" + "\24\161\1\u0115\31\161";
+
+ /**
+ * The transition table of the DFA
+ */
+ final private static int yytrans[] = yy_unpack(yy_packed);
+
+
+ /* error codes */
+ final private static int YY_UNKNOWN_ERROR = 0;
+ // final private static int YY_ILLEGAL_STATE = 1;
+ final private static int YY_NO_MATCH = 2;
+ final private static int YY_PUSHBACK_2BIG = 3;
+
+ /* error messages for the codes above */
+ final private static String YY_ERROR_MSG[] = {"Unkown internal scanner error", //$NON-NLS-1$
+ "Internal error: unknown state", //$NON-NLS-1$
+ "Error: could not match input", //$NON-NLS-1$
+ "Error: pushback value was too large" //$NON-NLS-1$
+ };
+
+ /**
+ * YY_ATTRIBUTE[aState] contains the attributes of state
+ * <code>aState</code>
+ */
+ private final static byte YY_ATTRIBUTE[] = {1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 9, 1, 9, 1, 1, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 9, 1, 9, 9, 1, 0, 1, 0, 1, 0, 0, 0, 9, 1, 1, 9, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 9, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 9, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 9, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 9, 0, 0, 9, 9, 9, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 9, 0, 1, 9, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 9, 9, 1, 1, 0, 9, 9, 9, 1, 1, 0, 1, 1, 9, 1, 1};
+
+ /** the input device */
+ private java.io.Reader yy_reader;
+
+ /** the current state of the DFA */
+ private int yy_state;
+
+ /** the current lexical state */
+ private int yy_lexical_state = YYINITIAL;
+
+ /**
+ * this buffer contains the current text to be matched and is the source
+ * of the yytext() string
+ */
+ private char yy_buffer[] = new char[16384];
+
+ /** the textposition at the last accepting state */
+ private int yy_markedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int yy_pushbackPos;
+
+ /** the current text position in the buffer */
+ private int yy_currentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int yy_startRead;
+
+ /**
+ * endRead marks the last character in the buffer, that has been read from
+ * input
+ */
+ private int yy_endRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ private int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ private int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ // private int yycolumn;
+ /**
+ * yy_atBOL == true <=>the scanner is currently at the beginning of a line
+ */
+ // private boolean yy_atBOL;
+ /** yy_atEOF == true <=>the scanner has returned a value for EOF */
+ private boolean yy_atEOF;
+
+ /** denotes if the user-EOF-code has already been executed */
+ private boolean yy_eof_done;
+
+ /* user code: */
+ private int fTokenCount = 0;
+
+ // required holders for white-space compacting
+ private boolean fShouldLoadBuffered = false;
+ private String fBufferedContext = null;
+ private int fBufferedStart = 1;
+ private int fBufferedLength = 0;
+ private ContextRegionContainer fBufferedEmbeddedContainer = null;
+ private String f_context = null;
+
+ // state stack for handling embedded regions
+ private IntStack fStateStack = new IntStack();
+ // a "hint" as to what an embedded region should be evaluated
+ String fEmbeddedHint = UNDEFINED;
+ // a "hint" as to what state to enter once an embedded region has
+ // been completed
+ int fEmbeddedPostState = YYINITIAL;
+ // the container used to create embedded regions
+ private ContextRegionContainer fEmbeddedContainer = null;
+ private static final String PROXY_CONTEXT = "PROXY_CONTEXT";
+
+ private String context = null;
+ private int start = 0;
+ private int textLength = 0;
+ private int length = 0;
+
+ // offset for tracking position specific block tags
+ private int fOffset = 0;
+
+ // the name of the current tag being opened
+ private String fCurrentTagName = null;
+
+ // the list of tag name BlockMarkers
+ private List fBlockMarkers = new ArrayList();
+
+ // required to not seek text blocks on an end tag
+ private boolean fIsBlockingEnabled = false;
+ private boolean fIsCaseSensitiveBlocking = true;
+
+ private XMLParserRegionFactory fRegionFactory = new XMLParserRegionFactory();
+
+ static final String rcsver = "$Id: XMLTokenizer.java,v 1.3 2004/11/11 09:05:07 david_williams Exp $";//$NON-NLS-1$
+
+ /**
+ * user method
+ */
+ public final void addBlockMarker(BlockMarker marker) {
+ if (containsTagName(marker.getTagName()))
+ return;
+ fBlockMarkers.add(marker);
+ }
+
+ /**
+ * user method
+ */
+ public final void removeBlockMarker(BlockMarker marker) {
+ fBlockMarkers.remove(marker);
+ }
+
+ /**
+ * user method
+ */
+ public final void removeBlockMarker(String tagname) {
+ if (fBlockMarkers != null) {
+ Iterator blocks = fBlockMarkers.iterator();
+ while (blocks.hasNext()) {
+ if (((BlockMarker) blocks.next()).getTagName().equals(tagname))
+ blocks.remove();
+ }
+ }
+ }
+
+ /* user method */
+ public final boolean isCaseSensitiveBlocking() {
+ return fIsCaseSensitiveBlocking;
+ }
+
+ /* user method */
+ public final void setCaseSensitiveBlocking(boolean newValue) {
+ fIsCaseSensitiveBlocking = newValue;
+ }
+
+ /* user method */
+ public boolean getBlockMarkerCaseSensitivity() {
+ return getBlockMarkerCaseSensitivity(fCurrentTagName);
+ }
+
+ /* user method */
+ public boolean getBlockMarkerCaseSensitivity(String name) {
+ Iterator iterator = fBlockMarkers.iterator();
+ while (iterator.hasNext()) {
+ BlockMarker marker = (BlockMarker) iterator.next();
+ boolean casesensitive = marker.isCaseSensitive();
+ if (casesensitive && marker.getTagName().equals(name))
+ return casesensitive;
+ else if (!casesensitive && marker.getTagName().equalsIgnoreCase(name))
+ return casesensitive;
+ }
+ return true;
+ }
+
+ /* user method */
+ public String getBlockMarkerContext() {
+ return getBlockMarkerContext(fCurrentTagName);
+ }
+
+ /* user method */
+ public String getBlockMarkerContext(String name) {
+ Iterator iterator = fBlockMarkers.iterator();
+ while (iterator.hasNext()) {
+ BlockMarker marker = (BlockMarker) iterator.next();
+ if (marker.getTagName().equals(name))
+ return marker.getContext();
+ }
+ return BLOCK_TEXT;
+ }
+
+ /* user method */
+ public List getBlockMarkers() {
+ return fBlockMarkers;
+ }
+
+ /* user method */
+ public final int getOffset() {
+ return fOffset + yychar;
+ }
+
+ private final boolean isBlockMarker() {
+ return isBlockMarker(fCurrentTagName);
+ }
+
+ private final boolean isBlockMarker(String tagName) {
+ if (!fIsBlockingEnabled)
+ return false;
+ return containsTagName(tagName);
+ }
+
+ /**
+ * user method
+ */
+ public final void beginBlockTagScan(String newTagName) {
+ beginBlockMarkerScan(newTagName, BLOCK_TEXT);
+ }
+
+ /**
+ * user method
+ *
+ * Special tokenizer setup. Allows tokenization to be initiated at the
+ * start of a text block within a "newTagName" tag.
+ *
+ * Example: Tokenizer toker = new Tokenizer();
+ * toker.setCaseSensitiveBlocking(false); toker.reset(new
+ * java.io.StringReader("afiuhqwkejhtasihgalkwhtq </scripter> </scr>
+ * </script>asgdasga")); toker.beginBlockMarkerScan("script", BLOCK_TEXT);
+ * toker.getRegions();
+ *
+ * Returns: BLOCK_TEXT: 0-40 XML_END_TAG_OPEN: 41-42 XML_TAG_NAME: 43-48
+ * XML_TAG_CLOSE: 49-49 XML_CONTENT: 50-57
+ *
+ */
+ public final void beginBlockMarkerScan(String newTagName, String blockcontext) {
+ yybegin(ST_BLOCK_TAG_SCAN);
+ fCurrentTagName = newTagName;
+ }
+
+ /**
+ * Method doScan.
+ *
+ * Returns a context region for all of the text from the current position
+ * upto the end of input or to right *before* the first occurence of
+ * searchString
+ *
+ * @param searchString -
+ * target string to search for ex.: "-->", " </tagname"
+ * @param requireTailSeparator -
+ * whether the target must be immediately followed by
+ * whitespace or '>'
+ * @param context -
+ * the context of the scanned region if non-zero length
+ * @param exitState -
+ * the state to go to if the region was of non-zero length
+ * @param abortState -
+ * the state to go to if the searchString was found immediately
+ * @return String - the context found: the desired context on a non-zero
+ * length match, the abortContext on immediate success
+ * @throws IOException
+ */
+ private final String doScan(String searchString, boolean requireTailSeparator, String searchContext, int exitState, int immediateFallbackState) throws IOException {
+ boolean stillSearching = true;
+ // Disable further block (probably)
+ fIsBlockingEnabled = false;
+ int searchStringLength = searchString.length();
+ int n = 0;
+ char lastCheckChar;
+ int i;
+ boolean same = false;
+ while (stillSearching) {
+ n = 0;
+ // Ensure that enough data from the input exists to compare
+ // against the search String.
+ n = yy_advance();
+ while (n != YYEOF && yy_currentPos < searchStringLength)
+ n = yy_advance();
+ // If the input was too short or we've exhausted the input, stop
+ // immediately.
+ if (n == YYEOF) {
+ stillSearching = false;
+ } else {
+ same = true;
+ // Ensure that we've not encountered a complete block (<%%>)
+ // that was *shorter* than the closeTagString and
+ // thus found twice at current-targetLength [since the first
+ // scan would have come out this far anyway].
+ // Check the characters in the target versus the last
+ // targetLength characters read from the buffer
+ // and see if it matches
+
+ // safety check for array accesses (yy_currentPos is the
+ // *last* character we can check against)
+ if (yy_currentPos >= searchStringLength && yy_currentPos <= yy_buffer.length) {
+ for (i = 0; i < searchStringLength; i++) {
+ if (same && fIsCaseSensitiveBlocking)
+ same = yy_buffer[i + yy_currentPos - searchStringLength] == searchString.charAt(i);
+ else if (same && !fIsCaseSensitiveBlocking)
+ same = Character.toLowerCase(yy_buffer[i + yy_currentPos - searchStringLength]) == Character.toLowerCase(searchString.charAt(i));
+ }
+ }
+ // safety check failed; no match is possible right now
+ else {
+ same = false;
+ }
+ if (same && requireTailSeparator && yy_currentPos < yy_buffer.length) {
+ // Additional check for close tags to ensure that
+ // targetString="</script" doesn't match
+ // "</scriptS"
+ lastCheckChar = yy_buffer[yy_currentPos];
+ // Succeed on "</script>" and "</script "
+ if (lastCheckChar == '>' || Character.isWhitespace(lastCheckChar))
+ stillSearching = false;
+ } else {
+ stillSearching = !same || (yy_currentPos < yy_startRead + searchStringLength);
+ }
+ }
+ }
+ if (n != YYEOF || same) {
+ // We've stopped short of the end or definitely found a match
+ yy_markedPos = yy_currentPos - searchStringLength;
+ yy_currentPos = yy_markedPos + 1;
+ // If the searchString occurs at the very beginning of what would
+ // have
+ // been a Block, resume scanning normally immediately
+ if (yy_markedPos == yy_startRead) {
+ yybegin(immediateFallbackState);
+ return primGetNextToken();
+ }
+ } else {
+ // We ran through the rest of the input
+ yy_markedPos = yy_currentPos;
+ yy_currentPos++;
+ }
+ yybegin(exitState);
+ // If the ending occurs at the very beginning of what would have
+ // been a Block, resume scanning normally immediately
+ if (yy_markedPos == yy_startRead)
+ return primGetNextToken();
+ return searchContext;
+ }
+
+ /**
+ * user method
+ *
+ * A generic lookahead-like operation
+ */
+ private final String doBlockScan(String target, String targetContext, int immediateFallbackState) throws IOException {
+ return doScan(target, false, targetContext, immediateFallbackState, immediateFallbackState);
+ }
+
+ /**
+ * user method does a lookahead for the current tag name
+ */
+ private final String doBlockTagScan() throws IOException {
+ fIsCaseSensitiveBlocking = getBlockMarkerCaseSensitivity();
+ return doScan("</" + fCurrentTagName, true, getBlockMarkerContext(fCurrentTagName), YYINITIAL, YYINITIAL);
+ }
+
+ /**
+ * user method
+ *
+ * Converts the raw context String returned by the primGetNextToken()
+ * method into a full ITextRegion by pulling in values for the current
+ * offset within the scanning text.
+ *
+ * Returns null when EOF is encountered and attaches intermittently
+ * discovered whitespace onto the end of useful regions.
+ *
+ * Note that this algorithm caches the token following the one being
+ * returned so that whitespace can be collapsed.
+ */
+ public final ITextRegion getNextToken() throws IOException {
+ fEmbeddedContainer = null;
+ // load the starting non-whitespace token (assume that it is so)
+ if (fShouldLoadBuffered) {
+ if (fBufferedEmbeddedContainer != null) {
+ ITextRegion container = fBufferedEmbeddedContainer;
+ fBufferedEmbeddedContainer = null;
+ fShouldLoadBuffered = false;
+ return container;
+ }
+ context = fBufferedContext;
+ start = fBufferedStart;
+ textLength = length = fBufferedLength;
+ fShouldLoadBuffered = false;
+ } else {
+ context = primGetNextToken();
+ if (context == PROXY_CONTEXT) {
+ return fEmbeddedContainer;
+ } else if (context == XML_TAG_NAME) {
+ if (containsTagName(yy_buffer, yy_startRead, yy_markedPos - yy_startRead))
+ fCurrentTagName = yytext();
+ else
+ fCurrentTagName = null;
+ } else if (context == XML_TAG_OPEN) {
+ fIsBlockingEnabled = true;
+ } else if (context == XML_END_TAG_OPEN) {
+ fIsBlockingEnabled = false;
+ }
+ start = yychar;
+ textLength = length = yylength();
+ if (yy_atEOF) {
+ fTokenCount++;
+ return null;
+ }
+ }
+ // store the next token
+ f_context = primGetNextToken();
+ if (f_context == PROXY_CONTEXT) {
+ fBufferedEmbeddedContainer = fEmbeddedContainer;
+ fShouldLoadBuffered = true;
+ } else if (f_context == XML_TAG_NAME) {
+ if (containsTagName(yy_buffer, yy_startRead, yy_markedPos - yy_startRead))
+ fCurrentTagName = yytext();
+ else
+ fCurrentTagName = null;
+ } else if (f_context == XML_TAG_OPEN) {
+ fIsBlockingEnabled = true;
+ } else if (f_context == XML_END_TAG_OPEN) {
+ fIsBlockingEnabled = false;
+ }
+ fBufferedContext = f_context;
+ fBufferedStart = yychar;
+ fBufferedLength = yylength();
+ fShouldLoadBuffered = true;
+ if (fBufferedContext == WHITE_SPACE) {
+ fShouldLoadBuffered = false;
+ length += fBufferedLength;
+ }
+ if (context == null) {
+ // EOF
+ if (Debug.debugTokenizer) {
+ System.out.println(getClass().getName() + " discovered " + fTokenCount + " tokens."); //$NON-NLS-2$//$NON-NLS-1$
+ }
+ return null;
+ }
+ fTokenCount++;
+ return fRegionFactory.createToken(context, start, textLength, length, null, fCurrentTagName);
+ }
+
+ /* user method */
+ public XMLTokenizer() {
+ super();
+ }
+
+ /* user method */
+ public XMLTokenizer(char[] charArray) {
+ this(new CharArrayReader(charArray));
+ }
+
+ /* user method */
+ public void reset(char[] charArray) {
+ reset(new CharArrayReader(charArray), 0);
+ }
+
+ /* user method */
+ public void reset(char[] charArray, int newOffset) {
+ reset(new CharArrayReader(charArray), newOffset);
+ }
+
+ /* user method */
+ public void reset(java.io.InputStream in) {
+ reset(new java.io.InputStreamReader(in), 0);
+ }
+
+ /* user method */
+ public void reset(java.io.InputStream in, int newOffset) {
+ reset(new java.io.InputStreamReader(in), newOffset);
+ }
+
+ /* user method */
+ public void reset(java.io.Reader in) {
+ reset(in, 0);
+ }
+
+ /**
+ * user method *
+ *
+ * Reset internal counters and vars to "newly created" values, in the
+ * hopes that resetting a pre-existing tokenizer is faster than creating a
+ * new one.
+ *
+ * This method contains code blocks that were essentially duplicated from
+ * the <em>generated</em> output of this specification before this
+ * method was added. Those code blocks were under the above copyright.
+ */
+ public void reset(java.io.Reader in, int newOffset) {
+ if (Debug.debugTokenizer) {
+ System.out.println("resetting tokenizer");//$NON-NLS-1$
+ }
+ fOffset = newOffset;
+
+ /* the input device */
+ yy_reader = in;
+
+ /* the current state of the DFA */
+ yy_state = 0;
+
+ /* the current lexical state */
+ yy_lexical_state = YYINITIAL;
+
+ /*
+ * this buffer contains the current text to be matched and is the
+ * source of the yytext() string
+ */
+ java.util.Arrays.fill(yy_buffer, (char) 0);
+
+ /* the textposition at the last accepting state */
+ yy_markedPos = 0;
+
+ /* the textposition at the last state to be included in yytext */
+ yy_pushbackPos = 0;
+
+ /* the current text position in the buffer */
+ yy_currentPos = 0;
+
+ /* startRead marks the beginning of the yytext() string in the buffer */
+ yy_startRead = 0;
+
+ /**
+ * endRead marks the last character in the buffer, that has been read
+ * from input
+ */
+ yy_endRead = 0;
+
+ /* number of newlines encountered up to the start of the matched text */
+ yyline = 0;
+
+ /* the number of characters up to the start of the matched text */
+ yychar = 0;
+
+ /* yy_atEOF == true <=> the scanner has returned a value for EOF */
+ yy_atEOF = false;
+
+ /* denotes if the user-EOF-code has already been executed */
+ yy_eof_done = false;
+
+
+ /* user vars: */
+ fTokenCount = 0;
+
+ fShouldLoadBuffered = false;
+ fBufferedContext = null;
+ fBufferedStart = 1;
+ fBufferedLength = 0;
+ fStateStack = new IntStack();
+
+ context = null;
+ start = 0;
+ textLength = 0;
+ length = 0;
+
+ fEmbeddedContainer = null;
+ }
+
+ /**
+ * user method
+ *
+ * @see com.ibm.sed.parser.BlockTokenizer#newInstance()
+ */
+ public BlockTokenizer newInstance() {
+ XMLTokenizer newInstance = new XMLTokenizer();
+ // global tagmarkers can be shared; they have no state and
+ // are never destroyed (e.g. 'release')
+ for (int i = 0; i < fBlockMarkers.size(); i++) {
+ BlockMarker blockMarker = (BlockMarker) fBlockMarkers.get(i);
+ if (blockMarker.isGlobal())
+ newInstance.addBlockMarker(blockMarker);
+ }
+ return newInstance;
+ }
+
+ /* user method */
+ private final String scanXMLCommentText() throws IOException {
+ // Scan for '-->' and return the text up to that point as
+ // XML_COMMENT_TEXT unless the string occurs IMMEDIATELY, in which
+ // case change to the ST_XML_COMMENT_END state and return the next
+ // context as usual.
+ return doScan("-->", false, XML_COMMENT_TEXT, ST_XML_COMMENT_END, ST_XML_COMMENT_END);
+ }
+
+
+ /**
+ * Creates a new scanner There is also a java.io.InputStream version of
+ * this constructor.
+ *
+ * @param in
+ * the java.io.Reader to read input from.
+ */
+ public XMLTokenizer(java.io.Reader in) {
+ this.yy_reader = in;
+ }
+
+ /**
+ * Creates a new scanner. There is also java.io.Reader version of this
+ * constructor.
+ *
+ * @param in
+ * the java.io.Inputstream to read input from.
+ */
+ public XMLTokenizer(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed DFA transition table.
+ *
+ * @param packed
+ * the packed transition table
+ * @return the unpacked transition table
+ */
+ private static int[] yy_unpack(String packed) {
+ int[] trans = new int[9114];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 3174) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do
+ trans[j++] = value;
+ while (--count > 0);
+ }
+ return trans;
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed
+ * the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char[] yy_unpack_cmap(String packed) {
+ char[] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 1372) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do
+ map[j++] = value;
+ while (--count > 0);
+ }
+ return map;
+ }
+
+
+ /**
+ * Gets the next input character.
+ *
+ * @return the next character of the input stream, EOF if the end of the
+ * stream is reached.
+ * @exception IOException
+ * if any I/O-Error occurs
+ */
+ private int yy_advance() throws java.io.IOException {
+
+ /* standard case */
+ if (yy_currentPos < yy_endRead)
+ return yy_buffer[yy_currentPos++];
+
+ /* if the eof is reached, we don't need to work hard */
+ if (yy_atEOF)
+ return YYEOF;
+
+ /* otherwise: need to refill the buffer */
+
+ /* first: make room (if you can) */
+ if (yy_startRead > 0) {
+ System.arraycopy(yy_buffer, yy_startRead, yy_buffer, 0, yy_endRead - yy_startRead);
+
+ /* translate stored positions */
+ yy_endRead -= yy_startRead;
+ yy_currentPos -= yy_startRead;
+ yy_markedPos -= yy_startRead;
+ yy_pushbackPos -= yy_startRead;
+ yy_startRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (yy_currentPos >= yy_buffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[yy_currentPos * 2];
+ System.arraycopy(yy_buffer, 0, newBuffer, 0, yy_buffer.length);
+ yy_buffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = yy_reader.read(yy_buffer, yy_endRead, yy_buffer.length - yy_endRead);
+
+ if (numRead == -1)
+ return YYEOF;
+
+ yy_endRead += numRead;
+
+ return yy_buffer[yy_currentPos++];
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ final public void yyclose() throws java.io.IOException {
+ yy_atEOF = true; /* indicate end of file */
+ yy_endRead = yy_startRead; /* invalidate buffer */
+ yy_reader.close();
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ final public int yystate() {
+ return yy_lexical_state;
+ }
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState
+ * the new lexical state
+ */
+ final public void yybegin(int newState) {
+ yy_lexical_state = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ final public String yytext() {
+ return new String(yy_buffer, yy_startRead, yy_markedPos - yy_startRead);
+ }
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ final public int yylength() {
+ return yy_markedPos - yy_startRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning - from the SED JFlex
+ * skeleton
+ *
+ * @param errorCode
+ * the code of the errormessage to display
+ */
+ private void yy_ScanError(int errorCode) {
+ try {
+ Logger.log(Logger.ERROR, YY_ERROR_MSG[errorCode]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ Logger.log(Logger.ERROR, YY_ERROR_MSG[YY_UNKNOWN_ERROR]);
+ }
+ // DO NOT EXIT the VM on an error
+ // System.exit(1);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number
+ * the number of characters to be read again. This number must
+ * not be greater than yylength()!
+ */
+ void yypushback(int number) {
+ if (number > yylength())
+ yy_ScanError(YY_PUSHBACK_2BIG);
+
+ yy_markedPos -= number;
+ }
+
+ /**
+ * user method - skeleton.sed
+ */
+ protected final boolean containsTagName(char[] markerTagName, int offset, int tagnameLength) {
+ for (int j = 0; j < fBlockMarkers.size(); j++) {
+ BlockMarker marker = (BlockMarker) fBlockMarkers.get(j);
+ if (marker.getTagName().length() == tagnameLength) {
+ boolean matchesSoFar = true;
+ for (int i = 0; i < tagnameLength && matchesSoFar; i++) {
+ if (marker.isCaseSensitive()) {
+ if (marker.getTagName().charAt(i) != markerTagName[i + offset])
+ matchesSoFar = false;
+ } else {
+ if (Character.toLowerCase(marker.getTagName().charAt(i)) != Character.toLowerCase(markerTagName[i + offset]))
+ matchesSoFar = false;
+ }
+ }
+ if (matchesSoFar)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * user method - skeleton.sed
+ *
+ * Return ALL of the regions scannable within the remaining text Note: for
+ * verification use
+ */
+ public final List getRegions() {
+ List tokens = new ArrayList();
+ ITextRegion region = null;
+ try {
+ region = getNextToken();
+ while (region != null) {
+ if (region != null) {
+ tokens.add(region);
+ }
+ region = getNextToken();
+ }
+ } catch (StackOverflowError e) {
+ Logger.logException(getClass().getName() + ": input could not be tokenized correctly at position " + getOffset(), e);//$NON-NLS-1$
+ throw e;
+ } catch (Exception e) {
+ // Since this is convenience method and NOT the recommended
+ // way of getting tokens, many errors are simply hidden
+ Logger.logException("Exception not handled retrieving regions: " + e.getLocalizedMessage(), e);//$NON-NLS-1$
+ }
+ return tokens;
+ }
+
+ /**
+ * user method - skeleton.sed
+ */
+ private final void dump(String s) {
+ if (Debug.debugTokenizer) {
+ System.out.println(s + " (" + yychar + "-" + //$NON-NLS-2$//$NON-NLS-1$
+ (yylength() + yychar) + "):\'" + //$NON-NLS-1$
+ StringUtils.escape(yytext()) + "\'");//$NON-NLS-1$
+ }
+ }
+
+ /* user method - skeleton.sed */
+ public final boolean isEOF() {
+ return yy_atEOF;
+ }
+
+ /* user method - skeleton.sed */
+ protected final boolean containsTagName(String markerTagName) {
+ Iterator blocks = fBlockMarkers.iterator();
+ while (blocks.hasNext()) {
+ BlockMarker marker = (BlockMarker) blocks.next();
+ if (marker.isCaseSensitive()) {
+ if (marker.getTagName().equals(markerTagName))
+ return true;
+ } else {
+ if (marker.getTagName().equalsIgnoreCase(markerTagName))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Contains user EOF-code, which will be executed exactly once, when the
+ * end of file is reached
+ */
+ private void yy_do_eof() {
+ if (!yy_eof_done) {
+ yy_eof_done = true;
+ // do nothing, this is the downstream parser's job
+
+ }
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched, the end
+ * of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception IOException
+ * if any I/O-Error occurs
+ */
+ public String primGetNextToken() throws java.io.IOException {
+ int yy_input;
+ int yy_action;
+
+
+ while (true) {
+
+ yychar += yylength();
+
+ boolean yy_counted = false;
+ for (yy_currentPos = yy_startRead; yy_currentPos < yy_markedPos; yy_currentPos++) {
+ switch (yy_buffer[yy_currentPos]) {
+ case '\r' :
+ yyline++;
+ yy_counted = true;
+ break;
+ case '\n' :
+ if (yy_counted)
+ yy_counted = false;
+ else {
+ yyline++;
+ }
+ break;
+ default :
+ yy_counted = false;
+ }
+ }
+
+ if (yy_counted) {
+ if (yy_advance() == '\n')
+ yyline--;
+ if (!yy_atEOF)
+ yy_currentPos--;
+ }
+
+ yy_action = -1;
+
+ yy_currentPos = yy_startRead = yy_markedPos;
+
+ yy_state = yy_lexical_state;
+
+
+ yy_forAction : {
+ while (true) {
+
+ yy_input = yy_advance();
+
+ if (yy_input == YYEOF)
+ break yy_forAction;
+
+ int yy_next = yytrans[yy_rowMap[yy_state] + yycmap[yy_input]];
+ if (yy_next == -1)
+ break yy_forAction;
+ yy_state = yy_next;
+
+ int yy_attributes = YY_ATTRIBUTE[yy_state];
+ if ((yy_attributes & 1) > 0) {
+ yy_action = yy_state;
+ yy_markedPos = yy_currentPos;
+ if ((yy_attributes & 8) > 0)
+ break yy_forAction;
+ }
+
+ }
+ }
+
+
+ switch (yy_action) {
+
+ case 274 :
+ case 275 :
+ case 276 : {
+ if (Debug.debugTokenizer)
+ dump("\nCDATA start");//$NON-NLS-1$
+ fStateStack.push(yystate());
+ yybegin(ST_CDATA_TEXT);
+ return XML_CDATA_OPEN;
+ }
+ case 278 :
+ break;
+ case 268 : {
+ if (Debug.debugTokenizer)
+ dump("element");//$NON-NLS-1$
+ yybegin(ST_XML_ELEMENT_DECLARATION);
+ return XML_ELEMENT_DECLARATION;
+ }
+ case 279 :
+ break;
+ case 267 : {
+ if (Debug.debugTokenizer)
+ dump("attlist");//$NON-NLS-1$
+ yybegin(ST_XML_ATTLIST_DECLARATION);
+ return XML_ATTLIST_DECLARATION;
+ }
+ case 280 :
+ break;
+ case 266 : {
+ if (Debug.debugTokenizer)
+ dump("doctype");//$NON-NLS-1$
+ yybegin(ST_XML_DOCTYPE_DECLARATION);
+ return XML_DOCTYPE_DECLARATION;
+ }
+ case 281 :
+ break;
+ case 262 : {
+ if (Debug.debugTokenizer)
+ dump("doctype external id");//$NON-NLS-1$
+ fEmbeddedHint = XML_DOCTYPE_EXTERNAL_ID_PUBREF;
+ yybegin(ST_XML_DOCTYPE_ID_PUBLIC);
+ return XML_DOCTYPE_EXTERNAL_ID_PUBLIC;
+ }
+ case 282 :
+ break;
+ case 261 : {
+ if (Debug.debugTokenizer)
+ dump("doctype external id");//$NON-NLS-1$
+ fEmbeddedHint = XML_DOCTYPE_EXTERNAL_ID_SYSREF;
+ yybegin(ST_XML_DOCTYPE_ID_SYSTEM);
+ return XML_DOCTYPE_EXTERNAL_ID_SYSTEM;
+ }
+ case 283 :
+ break;
+ case 257 : {
+ if (Debug.debugTokenizer)
+ dump("DHTML processing instruction target");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_EQUALS;
+ yybegin(ST_DHTML_ATTRIBUTE_NAME);
+ return XML_TAG_NAME;
+ }
+ case 284 :
+ break;
+ case 234 : {
+ if (Debug.debugTokenizer)
+ dump("\nCharRef");//$NON-NLS-1$
+ return XML_CHAR_REFERENCE;
+ }
+ case 285 :
+ break;
+ case 231 : {
+ if (Debug.debugTokenizer)
+ dump("\ncomment start");//$NON-NLS-1$
+ fEmbeddedHint = XML_COMMENT_TEXT;
+ fEmbeddedPostState = ST_XML_COMMENT;
+ yybegin(ST_XML_COMMENT);
+ return XML_COMMENT_OPEN;
+ }
+ case 286 :
+ break;
+ case 213 : {
+ if (Debug.debugTokenizer)
+ dump("XML processing instruction target");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_EQUALS;
+ yybegin(ST_XML_PI_ATTRIBUTE_NAME);
+ return XML_TAG_NAME;
+ }
+ case 287 :
+ break;
+ case 212 : {
+ if (Debug.debugTokenizer)
+ dump("comment end");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ yybegin(YYINITIAL);
+ return XML_COMMENT_CLOSE;
+ }
+ case 288 :
+ break;
+ case 211 : {
+ if (Debug.debugTokenizer)
+ dump("CDATA end");//$NON-NLS-1$
+ yybegin(fStateStack.pop());
+ return XML_CDATA_CLOSE;
+ }
+ case 289 :
+ break;
+ case 210 : {
+ if (Debug.debugTokenizer)
+ dump("\nPEReference");//$NON-NLS-1$
+ return XML_PE_REFERENCE;
+ }
+ case 290 :
+ break;
+ case 207 : {
+ if (Debug.debugTokenizer)
+ dump("\nEntityRef");//$NON-NLS-1$
+ return XML_ENTITY_REFERENCE;
+ }
+ case 291 :
+ break;
+ case 158 :
+ case 172 :
+ case 180 : {
+ return XML_DOCTYPE_INTERNAL_SUBSET;
+ }
+ case 292 :
+ break;
+ case 146 : {
+ yybegin(YYINITIAL);
+ fEmbeddedHint = UNDEFINED;
+ if (Debug.debugTokenizer)
+ dump("empty tag close");//$NON-NLS-1$
+ return XML_EMPTY_TAG_CLOSE;
+ }
+ case 293 :
+ break;
+ case 131 : {
+ if (Debug.debugTokenizer)
+ dump("XML processing instruction end");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ yybegin(YYINITIAL);
+ return XML_PI_CLOSE;
+ }
+ case 294 :
+ break;
+ case 130 : {
+ // ended with nothing inside
+ fEmbeddedHint = UNDEFINED;
+ yybegin(YYINITIAL);
+ return XML_PI_CLOSE;
+ }
+ case 295 :
+ break;
+ case 127 : {
+ if (Debug.debugTokenizer)
+ dump("processing instruction end");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ yybegin(YYINITIAL);
+ return XML_PI_CLOSE;
+ }
+ case 296 :
+ break;
+ case 119 : {
+ fStateStack.push(yystate());
+ if (Debug.debugTokenizer)
+ dump("\ndeclaration start");//$NON-NLS-1$
+ yybegin(ST_XML_DECLARATION);
+ return XML_DECLARATION_OPEN;
+ }
+ case 297 :
+ break;
+ case 118 : {
+ if (Debug.debugTokenizer)
+ dump("\nprocessing instruction start");//$NON-NLS-1$
+ yybegin(ST_PI);
+ return XML_PI_OPEN;
+ }
+ case 298 :
+ break;
+ case 62 : {
+ if (Debug.debugTokenizer)
+ dump("DHTML processing instruction end");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ yybegin(YYINITIAL);
+ return XML_PI_CLOSE;
+ }
+ case 299 :
+ break;
+ case 56 :
+ case 58 :
+ case 59 :
+ case 60 :
+ case 135 : {
+ if (Debug.debugTokenizer)
+ dump("XML processing instruction attribute value");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_EQUALS;
+ yybegin(ST_XML_PI_ATTRIBUTE_NAME);
+ return XML_TAG_ATTRIBUTE_VALUE;
+ }
+ case 300 :
+ break;
+ case 55 : {
+ if (Debug.debugTokenizer)
+ dump("XML processing instruction '='");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_VALUE;
+ fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME;
+ yybegin(ST_XML_PI_ATTRIBUTE_VALUE);
+ return XML_TAG_ATTRIBUTE_EQUALS;
+ }
+ case 301 :
+ break;
+ case 54 : {
+ if (Debug.debugTokenizer)
+ dump("XML processing instruction attribute name");//$NON-NLS-1$
+ yybegin(ST_XML_PI_EQUALS);
+ return XML_TAG_ATTRIBUTE_NAME;
+ }
+ case 302 :
+ break;
+ case 50 :
+ case 51 :
+ case 52 : {
+ // block scan until close is found
+ return doScan("?>", false, XML_PI_CONTENT, ST_XML_PI_TAG_CLOSE, ST_XML_PI_TAG_CLOSE);
+ }
+ case 303 :
+ break;
+ case 49 : {
+ yybegin(ST_PI_CONTENT);
+ return WHITE_SPACE;
+ }
+ case 304 :
+ break;
+ case 46 :
+ case 47 :
+ case 48 :
+ case 128 :
+ case 129 :
+ case 214 :
+ case 236 :
+ case 248 : {
+ if (Debug.debugTokenizer)
+ dump("processing instruction target");//$NON-NLS-1$
+ fEmbeddedHint = XML_CONTENT;
+ yybegin(ST_PI_WS);
+ return XML_TAG_NAME;
+ }
+ case 305 :
+ break;
+ case 41 :
+ case 42 : {
+ if (Debug.debugTokenizer)
+ dump("comment content");//$NON-NLS-1$
+ return scanXMLCommentText();
+ }
+ case 306 :
+ break;
+ case 40 : {
+ if (Debug.debugTokenizer)
+ dump("LINE FEED");//$NON-NLS-1$
+ return WHITE_SPACE;
+ }
+ case 307 :
+ break;
+ case 0 :
+ case 31 :
+ case 121 :
+ case 123 :
+ case 205 :
+ case 206 :
+ case 233 : {
+ if (Debug.debugTokenizer)
+ dump("\nXML content");//$NON-NLS-1$
+ return XML_CONTENT;
+ }
+ case 308 :
+ break;
+ case 5 :
+ case 8 :
+ case 9 :
+ case 10 :
+ case 12 :
+ case 13 :
+ case 14 :
+ case 15 :
+ case 17 :
+ case 18 :
+ case 19 :
+ case 20 :
+ case 21 :
+ case 22 :
+ case 23 :
+ case 24 :
+ case 25 :
+ case 26 :
+ case 28 :
+ case 45 : {
+ if (Debug.debugTokenizer)
+ dump("white space");//$NON-NLS-1$
+ return WHITE_SPACE;
+ }
+ case 309 :
+ break;
+ case 16 :
+ case 70 : {
+ if (Debug.debugTokenizer)
+ dump("inappropriate tag name");//$NON-NLS-1$
+ yybegin(YYINITIAL);
+ return XML_CONTENT;
+ }
+ case 310 :
+ break;
+ case 27 :
+ case 105 :
+ case 106 :
+ case 191 :
+ case 226 :
+ case 244 :
+ case 254 :
+ case 263 :
+ case 269 :
+ case 272 : {
+ if (Debug.debugTokenizer)
+ dump("elementdecl contentspec");//$NON-NLS-1$
+ return XML_ELEMENT_DECL_CONTENT;
+ }
+ case 311 :
+ break;
+ case 29 :
+ case 112 :
+ case 113 :
+ case 202 :
+ case 230 :
+ case 246 :
+ case 255 :
+ case 264 :
+ case 270 :
+ case 273 : {
+ if (Debug.debugTokenizer)
+ dump("attlist contentspec");//$NON-NLS-1$
+ return XML_ATTLIST_DECL_CONTENT;
+ }
+ case 312 :
+ break;
+ case 32 :
+ case 71 :
+ case 82 : {
+ if (Debug.debugTokenizer)
+ dump("\nstart tag open");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_NAME;
+ fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME;
+ yybegin(ST_XML_TAG_NAME);
+ return XML_TAG_OPEN;
+ }
+ case 313 :
+ break;
+ case 33 :
+ case 34 :
+ case 37 :
+ case 38 :
+ case 39 :
+ case 43 :
+ case 44 :
+ case 53 :
+ case 57 :
+ case 61 :
+ case 63 :
+ case 67 :
+ case 73 :
+ case 79 :
+ case 84 :
+ case 85 :
+ case 86 :
+ case 87 :
+ case 89 :
+ case 90 :
+ case 92 :
+ case 97 :
+ case 102 :
+ case 109 : {
+ if (Debug.debugTokenizer)
+ System.out.println("!!!unexpected!!!: \"" + yytext() + "\":" + //$NON-NLS-2$//$NON-NLS-1$
+ yychar + "-" + (yychar + yylength()));//$NON-NLS-1$
+ return UNDEFINED;
+ }
+ case 314 :
+ break;
+ case 35 :
+ case 36 : {
+ if (Debug.debugTokenizer)
+ dump("CDATA text");//$NON-NLS-1$
+ fEmbeddedHint = XML_CDATA_TEXT;
+ fEmbeddedPostState = ST_CDATA_TEXT;
+ String blockContext = doBlockScan("]]>", XML_CDATA_TEXT, ST_CDATA_END);//$NON-NLS-1$
+ if (blockContext == XML_CDATA_TEXT)
+ yybegin(ST_CDATA_END);
+ return blockContext;
+ }
+ case 315 :
+ break;
+ case 64 : {
+ if (Debug.debugTokenizer)
+ dump("DHTML processing instruction attribute name");//$NON-NLS-1$
+ yybegin(ST_DHTML_EQUALS);
+ return XML_TAG_ATTRIBUTE_NAME;
+ }
+ case 316 :
+ break;
+ case 65 : {
+ if (Debug.debugTokenizer)
+ dump("DHTML processing instruction '='");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_VALUE;
+ fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME;
+ yybegin(ST_DHTML_ATTRIBUTE_VALUE);
+ return XML_TAG_ATTRIBUTE_EQUALS;
+ }
+ case 317 :
+ break;
+ case 66 :
+ case 68 :
+ case 69 :
+ case 143 : {
+ if (Debug.debugTokenizer)
+ dump("DHTML processing instruction attribute value");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_EQUALS;
+ yybegin(ST_DHTML_ATTRIBUTE_NAME);
+ return XML_TAG_ATTRIBUTE_VALUE;
+ }
+ case 318 :
+ break;
+ case 72 : {
+ if (Debug.debugTokenizer)
+ dump("tag close");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ if (isBlockMarker()) {
+ fEmbeddedHint = getBlockMarkerContext();
+ fEmbeddedPostState = ST_BLOCK_TAG_SCAN;
+ yybegin(ST_BLOCK_TAG_SCAN);
+ } else
+ yybegin(YYINITIAL);
+ return XML_TAG_CLOSE;
+ }
+ case 319 :
+ break;
+ case 74 :
+ case 75 : {
+ if (Debug.debugTokenizer)
+ dump("tag name");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_EQUALS;
+ yybegin(ST_XML_ATTRIBUTE_NAME);
+ return XML_TAG_NAME;
+ }
+ case 320 :
+ break;
+ case 76 : {
+ if (Debug.debugTokenizer)
+ dump("attr name");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME;
+ yybegin(ST_XML_EQUALS);
+ return XML_TAG_ATTRIBUTE_NAME;
+ }
+ case 321 :
+ break;
+ case 77 : {
+ if (Debug.debugTokenizer)
+ dump("equals");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_VALUE;
+ fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME;
+ yybegin(ST_XML_ATTRIBUTE_VALUE);
+ return XML_TAG_ATTRIBUTE_EQUALS;
+ }
+ case 322 :
+ break;
+ case 78 :
+ case 80 :
+ case 81 :
+ case 150 : {
+ if (Debug.debugTokenizer)
+ dump("attr value");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME;
+ fEmbeddedPostState = ST_XML_EQUALS;
+ yybegin(ST_XML_ATTRIBUTE_NAME);
+ return XML_TAG_ATTRIBUTE_VALUE;
+ }
+ case 323 :
+ break;
+ case 83 : {
+ if (Debug.debugTokenizer)
+ dump("declaration end");//$NON-NLS-1$
+ if (Debug.debugTokenizer) {
+ if (fStateStack.peek() != YYINITIAL)
+ System.out.println("end embedded region");//$NON-NLS-1$
+ }
+ yybegin(fStateStack.pop());
+ return XML_DECLARATION_CLOSE;
+ }
+ case 324 :
+ break;
+ case 88 : {
+ if (Debug.debugTokenizer)
+ dump("doctype type");//$NON-NLS-1$
+ yybegin(ST_XML_DOCTYPE_EXTERNAL_ID);
+ return XML_DOCTYPE_NAME;
+ }
+ case 325 :
+ break;
+ case 91 :
+ case 93 :
+ case 94 :
+ case 95 :
+ case 164 :
+ case 165 :
+ case 168 :
+ case 169 :
+ case 221 : {
+ if (Debug.debugTokenizer)
+ dump("doctype public reference");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ fEmbeddedPostState = YYINITIAL;
+ yybegin(ST_XML_DOCTYPE_ID_SYSTEM);
+ return XML_DOCTYPE_EXTERNAL_ID_PUBREF;
+ }
+ case 326 :
+ break;
+ case 96 :
+ case 98 :
+ case 99 :
+ case 100 :
+ case 176 : {
+ if (Debug.debugTokenizer)
+ dump("doctype system reference");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ fEmbeddedPostState = YYINITIAL;
+ yybegin(ST_XML_DECLARATION_CLOSE);
+ return XML_DOCTYPE_EXTERNAL_ID_SYSREF;
+ }
+ case 327 :
+ break;
+ case 101 :
+ case 103 :
+ case 104 :
+ case 184 :
+ case 185 :
+ case 188 :
+ case 189 :
+ case 224 : {
+ if (Debug.debugTokenizer)
+ dump("elementdecl name");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ fEmbeddedPostState = YYINITIAL;
+ yybegin(ST_XML_ELEMENT_DECLARATION_CONTENT);
+ return XML_ELEMENT_DECL_NAME;
+ }
+ case 328 :
+ break;
+ case 107 : {
+ if (Debug.debugTokenizer)
+ dump("elementdecl close");//$NON-NLS-1$
+ if (Debug.debugTokenizer) {
+ if (fStateStack.peek() != YYINITIAL)
+ System.out.println("end embedded region");//$NON-NLS-1$
+ }
+ yybegin(fStateStack.pop());
+ return XML_DECLARATION_CLOSE;
+ }
+ case 329 :
+ break;
+ case 108 :
+ case 110 :
+ case 111 :
+ case 195 :
+ case 196 :
+ case 199 :
+ case 200 :
+ case 228 : {
+ if (Debug.debugTokenizer)
+ dump("attlist name");//$NON-NLS-1$
+ fEmbeddedHint = UNDEFINED;
+ fEmbeddedPostState = YYINITIAL;
+ yybegin(ST_XML_ATTLIST_DECLARATION_CONTENT);
+ return XML_ATTLIST_DECL_NAME;
+ }
+ case 330 :
+ break;
+ case 114 : {
+ if (Debug.debugTokenizer)
+ dump("attlist close");//$NON-NLS-1$
+ if (Debug.debugTokenizer) {
+ if (fStateStack.peek() != YYINITIAL)
+ System.out.println("end embedded region");//$NON-NLS-1$
+ }
+ yybegin(fStateStack.pop());
+ return XML_DECLARATION_CLOSE;
+ }
+ case 331 :
+ break;
+ case 117 : {
+ if (Debug.debugTokenizer)
+ dump("\nend tag open");//$NON-NLS-1$
+ fEmbeddedHint = XML_TAG_NAME;
+ fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME;
+ yybegin(ST_XML_TAG_NAME);
+ return XML_END_TAG_OPEN;
+ }
+ case 332 :
+ break;
+ case 115 :
+ case 116 : {
+ return doBlockTagScan();
+ }
+ case 333 :
+ break;
+ default :
+ if (yy_input == YYEOF && yy_startRead == yy_currentPos) {
+ yy_atEOF = true;
+ yy_do_eof();
+ return null;
+ } else {
+ yy_ScanError(YY_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java
new file mode 100644
index 0000000000..2a577768b8
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+
+public class AttributeEqualsRegion implements ITextRegion {
+ static private final byte fTextLength = 1;
+ static private final String fType = XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS;
+ private short fLength;
+ private int fStart;
+
+
+ public AttributeEqualsRegion() {
+ super();
+ }
+
+ public AttributeEqualsRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fLength = (short) length;
+ }
+
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ public void adjustTextLength(int i) {
+ // not supported
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = (short) region.getLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // can never be updated
+ return null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java
new file mode 100644
index 0000000000..fd678bd02c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.Utilities;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class AttributeNameRegion implements ITextRegion {
+ // specify correct type
+ static private final String fType = XMLRegionContext.XML_TAG_ATTRIBUTE_NAME;
+ private int fLength;
+ private int fStart;
+ private int fTextLength;
+
+ public AttributeNameRegion() {
+ super();
+ }
+
+ public AttributeNameRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fTextLength = textLength;
+ fLength = length;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += 1;
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ fTextLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ RegionChangedEvent result = null;
+ // if the region is an easy type (e.g. attribute value),
+ // and the requested changes are all
+ // alphanumeric, then make the change here locally.
+ // (This can obviously be made more sophisticated as the need arises,
+ // but should
+ // always follow this pattern.)
+ if (Debug.debugStructuredDocument) {
+ System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$
+ System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$
+ }
+ boolean canHandle = false;
+ // note: we'll always handle deletes from these
+ // regions ... if its already that region,
+ // deleting something from it won't change its
+ // type. (remember, the calling program needs
+ // to insure we are not called, if not all contained
+ // on one region.
+ if ((changes == null) || (changes.length() == 0)) {
+ // delete case
+ // We can not do the quick delete, if
+ // if all the text in a region is to be deleted.
+ // Or, if the delete starts in the white space region.
+ // In these cases, a reparse is needed.
+ // Minor note, we use textEnd-start since it always
+ // less than or equal to end-start. This might
+ // cause us to miss a few cases we could have handled,
+ // but will prevent us from trying to handle funning cases
+ // involving whitespace.
+ if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) {
+ canHandle = false;
+ } else {
+ canHandle = true;
+ }
+ } else {
+ if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) {
+ canHandle = true;
+ } else {
+ canHandle = false;
+ }
+
+ }
+ if (canHandle) {
+ // at this point, we still have the old region. We won't create a
+ // new instance, we'll just update the one we have, by changing
+ // its end postion,
+ // The parent flatnode, upon return, has responsibility
+ // for updating sibling regions.
+ // and in turn, the structuredDocument itself has responsibility
+ // for
+ // updating the text store and down stream flatnodes.
+ if (Debug.debugStructuredDocument) {
+ System.out.println("change handled by region"); //$NON-NLS-1$
+ }
+ int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace);
+ // Note: we adjust both end and text end, because for any change
+ // that is in only the trailing whitespace region, we should not
+ // do a quick change,
+ // so 'canHandle' should have been false for those case.
+ // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above
+ // If we are handling as whitespace, there is no need to increase
+ // the text length, only
+ // the total length is changing.
+ if (!RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) {
+ fTextLength += lengthDifference;
+ }
+ fLength += lengthDifference;
+ result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace);
+ }
+
+ return result;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java
new file mode 100644
index 0000000000..03eb4634da
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.Utilities;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class AttributeValueRegion implements ITextRegion {
+ // specify correct type
+ static private final String fType = XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE;
+ private int fLength;
+ private int fStart;
+ private int fTextLength;
+
+ public AttributeValueRegion() {
+ super();
+ }
+
+ public AttributeValueRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fTextLength = textLength;
+ fLength = length;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += 1;
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ fTextLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ RegionChangedEvent result = null;
+ // if the region is an easy type (e.g. attribute value),
+ // and the requested changes are all
+ // alphanumeric, then make the change here locally.
+ // (This can obviously be made more sophisticated as the need arises,
+ // but should
+ // always follow this pattern.)
+ if (Debug.debugStructuredDocument) {
+ System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$
+ System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$
+ }
+ boolean canHandle = false;
+ // note: we'll always handle deletes from these
+ // regions ... if its already that region,
+ // deleting something from it won't change its
+ // type. (remember, the calling program needs
+ // to insure we are not called, if not all contained
+ // on one region.
+ if ((changes == null) || (changes.length() == 0)) {
+ // delete case
+ // We can not do the quick delete, if
+ // if all the text in a region is to be deleted.
+ // Or, if the delete starts in the white space region.
+ // In these cases, a reparse is needed.
+ // Minor note, we use textEnd-start since it always
+ // less than or equal to end-start. This might
+ // cause us to miss a few cases we could have handled,
+ // but will prevent us from trying to handle funning cases
+ // involving whitespace.
+ if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) {
+ canHandle = false;
+ } else {
+ canHandle = true;
+ }
+ } else {
+ if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) {
+ canHandle = true;
+ } else {
+ canHandle = false;
+ }
+ }
+ if (canHandle) {
+ // at this point, we still have the old region. We won't create a
+ // new instance, we'll just update the one we have, by changing
+ // its end postion,
+ // The parent flatnode, upon return, has responsibility
+ // for updating sibling regions.
+ // and in turn, the structuredDocument itself has responsibility
+ // for
+ // updating the text store and down stream flatnodes.
+ if (Debug.debugStructuredDocument) {
+ System.out.println("change handled by region"); //$NON-NLS-1$
+ }
+ int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace);
+ // Note: we adjust both end and text end, because for any change
+ // that is in only the trailing whitespace region, we should not
+ // do a quick change,
+ // so 'canHandle' should have been false for those case.
+ // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above
+ // If we are handling as whitespace, there is no need to increase
+ // the text length, only
+ // the total length is changing.
+ if (!RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) {
+ fTextLength += lengthDifference;
+ }
+ // update length (and end) after above check for white space,
+ // since
+ // it looks to determine if at end of region.
+ fLength += lengthDifference;
+ result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace);
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java
new file mode 100644
index 0000000000..b382257d5a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.internal.parser.ForeignRegion;
+
+
+
+public class BlockTextRegion extends ForeignRegion {
+
+ /**
+ * BlockTextRegion constructor comment.
+ */
+ public BlockTextRegion() {
+ super();
+ }
+
+ public BlockTextRegion(String newContext, int newStart, int newTextLength, int newLength) {
+ super(newContext, newStart, newTextLength, newLength);
+ }
+
+ public BlockTextRegion(String newContext, int newStart, int newTextLength, int newLength, String newLanguage) {
+ super(newContext, newStart, newTextLength, newLength, newLanguage);
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java
new file mode 100644
index 0000000000..291a3411e7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+/**
+ *
+ * This class is not intended to be used, its just present to server as a
+ * generic starting point for adding new specific region types.
+ */
+
+public class GenericTemplateRegion implements ITextRegion {
+ // specify correct type
+ static private final String fType = XMLRegionContext.UNDEFINED;
+ private int fLength;
+ private int fStart;
+ private int fTextLength;
+
+
+ public GenericTemplateRegion() {
+ super();
+ }
+
+ public GenericTemplateRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fTextLength = textLength;
+ fLength = length;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += 1;
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ fTextLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // can never be updated
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java
new file mode 100644
index 0000000000..9693beb913
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.text.ITextRegion;
+
+
+public class RegionToStringUtil {
+ static public String toString(ITextRegion region) {
+ String className = region.getClass().getName();
+ String shortClassName = className.substring(className.lastIndexOf(".") + 1); //$NON-NLS-1$
+ // ==> // String resultText = null;
+ String result = shortClassName + "--> " + region.getType() + ": " + region.getStart() + "-" + region.getTextEnd() + (region.getTextEnd() != region.getEnd() ? ("/" + region.getEnd()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ // NOTE: if the document held by any region has been updated and the
+ // region offsets have not
+ // yet been updated, the output from this method invalid.
+ //return com.ibm.sed.util.StringUtils.escape("('"+(getFirstRegion()
+ // == null || document == null? "" :
+ // getText(getFirstRegion()))+"'"+getStart()+" -
+ // "+getEnd()+"'"+(getClose() == null || document == null ||
+ // getRegions().size()<2 ? "" : getText(getClose()))+"')
+ // "+getRegions());
+ return result;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java
new file mode 100644
index 0000000000..8692688ea3
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.Utilities;
+
+
+/**
+ *
+ * This is a utility class to centralize 'region' update. Note: care must be
+ * taken that is is not used for StructuredDocumentRegions, or container
+ * regions, its only for "token regions"
+ *
+ */
+public class RegionUpdateRule {
+
+ static public boolean allLetterOrDigit(String changes) {
+ boolean result = true;
+ for (int i = 0; i < changes.length(); i++) {
+ // TO_DO_FUTURE: check that a Java Letter or Digit is
+ // the same thing as an XML letter or digit
+ if (!(Character.isLetterOrDigit(changes.charAt(i)))) {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+
+ static public boolean allWhiteSpace(String changes) {
+ boolean result = true;
+ for (int i = 0; i < changes.length(); i++) {
+ if (!Character.isWhitespace(changes.charAt(i))) {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ }
+
+ static public boolean canHandleAsLetterOrDigit(ITextRegion region, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ if (parent == null)
+ return canHandleAsLetterOrDigit(region, changes, requestStart, lengthToReplace);
+ boolean result = false;
+ // Make sure we are in a non-white space area
+ if ((requestStart <= (parent.getTextEndOffset(region))) && (allLetterOrDigit(changes))) {
+ result = true;
+ }
+ return result;
+ }
+
+ static public boolean canHandleAsLetterOrDigit(ITextRegion region, String changes, int requestStart, int lengthToReplace) {
+ boolean result = false;
+ // Make sure we are in a non-white space area
+ if ((requestStart <= (region.getTextEnd())) && (allLetterOrDigit(changes))) {
+ result = true;
+ }
+ return result;
+ }
+
+ static public boolean canHandleAsWhiteSpace(ITextRegion region, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // we don't explect a null parent, but just in case!
+ // (in which case, we must be dealing with regions that are
+ // structuredDocumentRegions).
+ if (parent == null)
+ return canHandleAsWhiteSpace(region, changes, requestStart, lengthToReplace);
+ boolean result = false;
+ // if we are in the "white space" area of a region, then
+ // we don't want to handle, a reparse is needed.
+ // the white space region is consider anywhere that would
+ // leave whitespace between this character and the text part.
+ // and of course, we can insert whitespace in whitespace region
+ //
+ // if there is no whitespace in this region, no need to look further
+ if (region.getEnd() > region.getTextEnd()) {
+ // no need to add one to end of text, as we used to, since we
+ // change definition of length to equate to offset plus one.
+ if (requestStart > parent.getTextEndOffset(region)) {
+ // ok, we are in the whitespace region, so we can't handle,
+ // unless
+ // we are just inserting whitespace.
+ if (allWhiteSpace(changes)) {
+ result = true;
+ } else {
+ result = false;
+ }
+ }
+ }
+ return result;
+ }
+
+ static public boolean canHandleAsWhiteSpace(ITextRegion region, String changes, int requestStart, int lengthToReplace) {
+ boolean result = false;
+ // if we are in the "white space" area of a region, then
+ // we don't want to handle, a reparse is needed.
+ // the white space region is consider anywhere that would
+ // leave whitespace between this character and the text part.
+ // and of course, we can insert whitespace in whitespace region
+ //
+ // if there is no whitespace in this region, no need to look further
+ if (region.getEnd() > region.getTextEnd()) {
+ // no need to add one to end of text, as we used to, since we
+ // change definition of length to equate to offset plus one.
+ if (requestStart > region.getTextEnd()) {
+ // ok, we are in the whitespace region, so we can't handle,
+ // unless
+ // we are just inserting whitespace.
+ if (allWhiteSpace(changes)) {
+ result = true;
+ } else {
+ result = false;
+ }
+ }
+ }
+ return result;
+ }
+
+ // need an adjust text length API before this can be used
+ static public StructuredDocumentEvent updateModel(ITextRegion region, Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ RegionChangedEvent result = null;
+ // if the region is an easy type (e.g. attribute value),
+ // and the requested changes are all
+ // alphanumeric, then make the change here locally.
+ // (This can obviously be made more sophisticated as the need arises,
+ // but should
+ // always follow this pattern.)
+ if (Debug.debugStructuredDocument) {
+ System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$
+ System.out.println("\t\t\tregion type is " + region.getType()); //$NON-NLS-1$
+ }
+ boolean canHandle = false;
+ // note: we'll always handle deletes from these
+ // regions ... if its already that region,
+ // deleting something from it won't change its
+ // type. (remember, the calling program needs
+ // to insure we are not called, if not all contained
+ // on one region.
+ if ((changes == null) || (changes.length() == 0)) {
+ // delete case
+ // We can not do the quick delete, if
+ // if all the text in a region is to be deleted.
+ // Or, if the delete starts in the white space region.
+ // In these cases, a reparse is needed.
+ // Minor note, we use textEnd-start since it always
+ // less than or equal to end-start. This might
+ // cause us to miss a few cases we could have handled,
+ // but will prevent us from trying to handle funning cases
+ // involving whitespace.
+ if ((region.getStart() >= region.getTextEnd()) || (Math.abs(lengthToReplace) >= region.getTextEnd() - region.getStart())) {
+ canHandle = false;
+ } else {
+ canHandle = true;
+ }
+ } else {
+ if ((RegionUpdateRule.canHandleAsWhiteSpace(region, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(region, parent, changes, requestStart, lengthToReplace)) {
+ canHandle = true;
+ } else {
+ canHandle = false;
+ }
+ }
+ if (canHandle) {
+ // at this point, we still have the old region. We won't create a
+ // new instance, we'll just update the one we have, by changing
+ // its end postion,
+ // The parent flatnode, upon return, has responsibility
+ // for updating sibling regions.
+ // and in turn, the structuredDocument itself has responsibility
+ // for
+ // updating the text store and down stream flatnodes.
+ if (Debug.debugStructuredDocument) {
+ System.out.println("change handled by region"); //$NON-NLS-1$
+ }
+ int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace);
+ // Note: we adjust both end and text end, because for any change
+ // that is in only the trailing whitespace region, we should not
+ // do a quick change,
+ // so 'canHandle' should have been false for those case.
+ region.adjustLengthWith(lengthDifference);
+ // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above
+ // If we are handling as whitespace, there is no need to increase
+ // the text length, only
+ // the total length is changing.
+ if (!RegionUpdateRule.canHandleAsWhiteSpace(region, parent, changes, region.getStart(), lengthToReplace)) {
+ // region.adjustTextLength(lengthDifference);
+ }
+ result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, region, changes, requestStart, lengthToReplace);
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java
new file mode 100644
index 0000000000..87044ddc5c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class TagCloseRegion implements ITextRegion {
+ static private final byte fLength = 1;
+ static private final byte fTextLength = 1;
+ static private final String fType = XMLRegionContext.XML_TAG_CLOSE;
+ private int fStart;
+
+
+ public TagCloseRegion() {
+ super();
+ }
+
+ public TagCloseRegion(int start) {
+ this();
+ fStart = start;
+ }
+
+ public void adjustLengthWith(int i) {
+ throw new SourceEditingRuntimeException("invalid for this region type"); //$NON-NLS-1$
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ // not supported
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // can never be updated
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java
new file mode 100644
index 0000000000..f01e5b017a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class TagNameRegion implements ITextRegion {
+ static private final String fType = XMLRegionContext.XML_TAG_NAME;
+ private short fLength;
+ private int fStart;
+ private short fTextLength;
+
+
+ public TagNameRegion() {
+ super();
+ }
+
+ public TagNameRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fTextLength = (short) textLength;
+ fLength = (short) length;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += i;
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = (short) region.getLength();
+ fTextLength = (short) region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // can never be updated
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java
new file mode 100644
index 0000000000..f09c83dadd
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class TagOpenRegion implements ITextRegion {
+ static private final String fType = XMLRegionContext.XML_TAG_OPEN;
+ private int fLength;
+ private int fStart;
+ private int fTextLength;
+
+
+ public TagOpenRegion() {
+ super();
+ }
+
+ public TagOpenRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fTextLength = textLength;
+ fLength = length;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += 1;
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ fTextLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // can never be updated
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java
new file mode 100644
index 0000000000..2727095457
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+
+
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.Utilities;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class WhiteSpaceOnlyRegion implements ITextRegion {
+ static private final byte fTextLength = 0;
+
+ static private final String fType = XMLRegionContext.WHITE_SPACE;
+ protected int fLength;
+ protected int fStart;
+
+ public WhiteSpaceOnlyRegion(int start, int length) {
+ super();
+ fStart = start;
+ fLength = length;
+ }
+
+ public void adjust(int i) {
+ fStart += i;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ // not supported
+
+ }
+
+ public boolean contains(int position) {
+
+ return fStart <= position && position < fStart + fLength;
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public void setLength(int i) {
+ fLength = i;
+ }
+
+ public void setStart(int i) {
+ fStart = i;
+ }
+
+ public void setTextLength(short i) {
+ throw new SourceEditingRuntimeException("invalid call"); //$NON-NLS-1$
+ }
+
+ public void setType(String string) {
+ throw new SourceEditingRuntimeException("invalid call"); //$NON-NLS-1$
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ /**
+ * For this ITextRegion type, the start must in terms of what the region
+ * expects ... that is, its not document offset, but start relative to
+ * what ever contains it.
+ */
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // if the region is an easy type (e.g. attribute value),
+ // and the requested changes are all
+ // alphanumeric, then make the change here locally.
+ // (This can obviously be made more sophisticated as the need arises,
+ // but should
+ // always follow this pattern.)
+ if (Debug.debugStructuredDocument) {
+ System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$
+ System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$
+ }
+ boolean canHandle = false;
+ // note: we'll always handle deletes from these
+ // regions ... if its already that region,
+ // deleting something from it won't change its
+ // type. (remember, the calling program needs
+ // to insure we are not called, if not all contained
+ // on one region.
+ if ((changes == null) || (changes.length() == 0)) {
+ // delete case
+ // We can not do the quick delete, if
+ // if all the text in a region is to be deleted.
+ // Or, if the delete starts in the white space region.
+ // In these cases, a reparse is needed.
+ // Minor note, we use textEnd-start since it always
+ // less than or equal to end-start. This might
+ // cause us to miss a few cases we could have handled,
+ // but will prevent us from trying to handle funning cases
+ // involving whitespace.
+ if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) {
+ canHandle = false;
+ } else {
+ canHandle = true;
+ }
+ } else {
+ if (RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) {
+ canHandle = true;
+ } else {
+ canHandle = false;
+ }
+
+ }
+ RegionChangedEvent result = null;
+
+ if (canHandle) {
+ // at this point, we still have the old region. We won't create a
+ // new instance, we'll just update the one we have, by changing
+ // its end postion,
+ // The parent flatnode, upon return, has responsibility
+ // for updating sibling regions.
+ // and in turn, the structuredDocument itself has responsibility
+ // for
+ // updating the text store and down stream flatnodes.
+ if (Debug.debugStructuredDocument) {
+ System.out.println("change handled by region"); //$NON-NLS-1$
+ }
+ int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace);
+ // Note: we adjust both end and text end, because for any change
+ // that is in only the trailing whitespace region, we should not
+ // do a quick change,
+ // so 'canHandle' should have been false for those case.
+ fLength += lengthDifference;
+
+ result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace);
+ }
+
+ return result;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java
new file mode 100644
index 0000000000..e6f3cbecef
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.Utilities;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class XMLCDataTextRegion implements ITextRegion {
+ static private final String fType = XMLRegionContext.XML_CDATA_TEXT;
+ private int fLength;
+ private int fStart;
+ private int fTextLength;
+
+
+ public XMLCDataTextRegion() {
+ super();
+ }
+
+ public XMLCDataTextRegion(int start, int textLength, int length) {
+ this();
+ fStart = start;
+ fTextLength = textLength;
+ fLength = length;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += i;
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ fTextLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ // TODO: shouldn't cdata be like XML Content ... length and text
+ // length
+ // always be the same, regardless of whitespace?
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // TODO: this is a pretty lame method, since XML CData region can have
+ // a much
+ // better rule for region update, but this is what previous
+ // (unfactored)
+ // version had, so I'll carry it over, of now.
+ RegionChangedEvent result = null;
+ // if the region is an easy type (e.g. attribute value),
+ // and the requested changes are all
+ // alphanumeric, then make the change here locally.
+ // (This can obviously be made more sophisticated as the need arises,
+ // but should
+ // always follow this pattern.)
+ if (Debug.debugStructuredDocument) {
+ System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$
+ System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$
+ }
+ boolean canHandle = false;
+ // note: we'll always handle deletes from these
+ // regions ... if its already that region,
+ // deleting something from it won't change its
+ // type. (remember, the calling program needs
+ // to insure we are not called, if not all contained
+ // on one region.
+ if ((changes == null) || (changes.length() == 0)) {
+ // delete case
+ // We can not do the quick delete, if
+ // if all the text in a region is to be deleted.
+ // Or, if the delete starts in the white space region.
+ // In these cases, a reparse is needed.
+ // Minor note, we use textEnd-start since it always
+ // less than or equal to end-start. This might
+ // cause us to miss a few cases we could have handled,
+ // but will prevent us from trying to handle funning cases
+ // involving whitespace.
+ if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) {
+ canHandle = false;
+ } else {
+ canHandle = true;
+ }
+ } else {
+ if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) {
+ canHandle = true;
+ } else {
+ canHandle = false;
+ }
+
+ }
+ if (canHandle) {
+ // at this point, we still have the old region. We won't create a
+ // new instance, we'll just update the one we have, by changing
+ // its end postion,
+ // The parent flatnode, upon return, has responsibility
+ // for updating sibling regions.
+ // and in turn, the structuredDocument itself has responsibility
+ // for
+ // updating the text store and down stream flatnodes.
+ if (Debug.debugStructuredDocument) {
+ System.out.println("change handled by region"); //$NON-NLS-1$
+ }
+ int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace);
+ // Note: we adjust both end and text end, because for any change
+ // that is in only the trailing whitespace region, we should not
+ // do a quick change,
+ // so 'canHandle' should have been false for those case.
+ // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above
+ // If we are handling as whitespace, there is no need to increase
+ // the text length, only
+ // the total length is changing.
+ if (!RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) {
+ fTextLength += lengthDifference;
+ }
+ fLength += lengthDifference;
+ result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace);
+ }
+
+ return result;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java
new file mode 100644
index 0000000000..7155dfcedf
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.RegionChangedEvent;
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.util.Debug;
+import org.eclipse.wst.sse.core.util.Utilities;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+
+public class XMLContentRegion implements ITextRegion {
+ static private final String fType = XMLRegionContext.XML_CONTENT;
+ // length and textLength are always the same for content region
+ //private int fTextLength;
+ private int fLength;
+ private int fStart;
+
+
+ public XMLContentRegion() {
+ super();
+ }
+
+ public XMLContentRegion(int start, int length) {
+ this();
+ fStart = start;
+ fLength = length;
+ }
+
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ // not supported
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public int getTextEnd() {
+ return fStart + fLength;
+ }
+
+ public int getTextLength() {
+ return fLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // TODO: this is a pretty lame method, since XML Content can have a
+ // much
+ // better rule for region update, but this is what previous
+ // (unfactored)
+ // version had, so I'll carry it over, of now.
+ RegionChangedEvent result = null;
+ // if the region is an easy type (e.g. attribute value),
+ // and the requested changes are all
+ // alphanumeric, then make the change here locally.
+ // (This can obviously be made more sophisticated as the need arises,
+ // but should
+ // always follow this pattern.)
+ if (Debug.debugStructuredDocument) {
+ System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$
+ System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$
+ }
+ boolean canHandle = false;
+ // note: we'll always handle deletes from these
+ // regions ... if its already that region,
+ // deleting something from it won't change its
+ // type. (remember, the calling program needs
+ // to insure we are not called, if not all contained
+ // on one region.
+ if ((changes == null) || (changes.length() == 0)) {
+ // delete case
+ // We can not do the quick delete, if
+ // if all the text in a region is to be deleted.
+ // Or, if the delete starts in the white space region.
+ // In these cases, a reparse is needed.
+ // Minor note, we use textEnd-start since it always
+ // less than or equal to end-start. This might
+ // cause us to miss a few cases we could have handled,
+ // but will prevent us from trying to handle funning cases
+ // involving whitespace.
+ if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) {
+ canHandle = false;
+ } else {
+ canHandle = true;
+ }
+ } else {
+ if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) {
+ canHandle = true;
+ } else {
+ canHandle = false;
+ }
+
+ }
+ if (canHandle) {
+ // at this point, we still have the old region. We won't create a
+ // new instance, we'll just update the one we have, by changing
+ // its end postion,
+ // The parent flatnode, upon return, has responsibility
+ // for updating sibling regions.
+ // and in turn, the structuredDocument itself has responsibility
+ // for
+ // updating the text store and down stream flatnodes.
+ if (Debug.debugStructuredDocument) {
+ System.out.println("change handled by region"); //$NON-NLS-1$
+ }
+ int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace);
+ // Note: we adjust both end and text end, because for any change
+ // that is in only the trailing whitespace region, we should not
+ // do a quick change,
+ // so 'canHandle' should have been false for those case.
+ fLength += lengthDifference;
+ // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above
+ // If we are handling as whitespace, there is no need to increase
+ // the text length, only
+ // the total length is changing.
+ // don't need for content region
+ // if (!RegionUpdateRule.canHandleAsWhiteSpace(this, changes,
+ // fStart, lengthToReplace)) {
+ // fTextLength += lengthDifference;
+ // }
+ result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace);
+ }
+
+ return result;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java
new file mode 100644
index 0000000000..66d9ee9413
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.text.ITextRegion;
+
+public class XMLHeadParserFactory {
+ public ITextRegion createToken(String context, int start, int textLength, int length, String text) {
+ ITextRegion newRegion = null;
+ // if (context == XMLRegionContext.XML_CDATA_TEXT) {
+ newRegion = new XMLHeadParserRegion(context, start, textLength, length, text);
+ // }
+ return newRegion;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java
new file mode 100644
index 0000000000..98dad747b4
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+import org.eclipse.wst.sse.core.events.StructuredDocumentEvent;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+/**
+ *
+ * This class is not intended to be used, its just present to server as a
+ * generic starting point for adding new specific region types.
+ */
+
+public class XMLHeadParserRegion implements ITextRegion {
+ private int fLength;
+ private int fStart;
+ private String fText;
+ private int fTextLength;
+ // specify correct type
+ private String fType = XMLRegionContext.UNDEFINED;
+
+ public XMLHeadParserRegion() {
+ super();
+ }
+
+ public XMLHeadParserRegion(String context, int start, int textLength, int length, String text) {
+ this();
+ fType = context;
+ fStart = start;
+ fTextLength = textLength;
+ fLength = length;
+ fText = text;
+ }
+
+ public void adjustLengthWith(int i) {
+ fLength += i;
+
+ }
+
+ public void adjustStart(int i) {
+ fStart += i;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int)
+ */
+ public void adjustTextLength(int i) {
+ fTextLength += 1;
+
+ }
+
+ public void equatePositions(ITextRegion region) {
+ fStart = region.getStart();
+ fLength = region.getLength();
+ fTextLength = region.getTextLength();
+ }
+
+ public int getEnd() {
+ return fStart + fLength;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public int getStart() {
+ return fStart;
+ }
+
+ public String getText() {
+ return fText;
+ }
+
+ public int getTextEnd() {
+ return fStart + fTextLength;
+ }
+
+ public int getTextLength() {
+ return fTextLength;
+ }
+
+ public String getType() {
+ return fType;
+ }
+
+ public String toString() {
+ return RegionToStringUtil.toString(this);
+ }
+
+ public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) {
+ // can never be updated
+ return null;
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java
new file mode 100644
index 0000000000..6b03796502
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.parser.regions;
+
+
+
+import org.eclipse.wst.sse.core.internal.parser.ContextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.eclipse.wst.sse.core.text.ITextRegionContainer;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+/**
+ *
+ * This region factory is very specific to the parser output, and the specific
+ * implementation classes for various regions.
+ */
+
+public class XMLParserRegionFactory {
+
+ public XMLParserRegionFactory() {
+ super();
+ }
+
+ public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length) {
+ return this.createToken(parent, context, start, textLength, length, null, null);
+ }
+
+ public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length, String lang, String surroundingTag) {
+ ITextRegion newRegion = createToken(context, start, textLength, length);
+ // DW, 4/16/2003 token regions no longer have parents
+ //newRegion.setParent(parent);
+ return newRegion;
+ }
+
+ public ITextRegion createToken(String context, int start, int textLength, int length) {
+ return this.createToken(context, start, textLength, length, null, null);
+ }
+
+ public ITextRegion createToken(String context, int start, int textLength, int length, String lang, String surroundingTag) {
+ ITextRegion newRegion = null;
+ if (context == XMLRegionContext.XML_CDATA_TEXT) {
+ newRegion = new XMLCDataTextRegion(start, textLength, length);
+ } else if (context == XMLRegionContext.XML_CONTENT) {
+ newRegion = new XMLContentRegion(start, length);
+ } else if (context == XMLRegionContext.XML_TAG_NAME) {
+ newRegion = new TagNameRegion(start, textLength, length);
+ } else if (context == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) {
+ newRegion = new AttributeNameRegion(start, textLength, length);
+ } else if (context == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) {
+ newRegion = new AttributeEqualsRegion(start, textLength, length);
+ } else if (context == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
+ newRegion = new AttributeValueRegion(start, textLength, length);
+ } else if (context == XMLRegionContext.XML_TAG_OPEN) {
+ newRegion = new TagOpenRegion(start, textLength, length);
+ } else if (context == XMLRegionContext.XML_TAG_CLOSE) {
+ newRegion = new TagCloseRegion(start);
+ } else if (context == XMLRegionContext.WHITE_SPACE) {
+ newRegion = new WhiteSpaceOnlyRegion(start, length);
+ } else
+ // removed this condition during transition, and implemented in
+ // subclass
+ // if (context == XMLJSPRegionContexts.JSP_CONTENT) {
+ // newRegion = new JSPCodeRegion(context, start, textLength, length);
+ // } else
+ if (context == XMLRegionContext.BLOCK_TEXT) {
+ newRegion = new BlockTextRegion(context, start, textLength, length);
+ ((BlockTextRegion) newRegion).setSurroundingTag(surroundingTag);
+ } else {
+ newRegion = new ContextRegion(context, start, textLength, length);
+ }
+ return newRegion;
+ }
+
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java
new file mode 100644
index 0000000000..ed13b8a959
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.propagate;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.wst.sse.core.AbstractAdapterFactory;
+import org.eclipse.wst.sse.core.AdapterFactory;
+import org.eclipse.wst.sse.core.INodeAdapter;
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.PropagatingAdapter;
+import org.eclipse.wst.sse.core.PropagatingAdapterFactory;
+
+
+/**
+ * The PropagatingAdapterFactory is part of the "adapt on create" mechanism. A
+ * PropagatingAdapter, once added to a node, will cause proagating adapters to
+ * be created for all child nodes. A side effect of creating a
+ * PropagatingAdapter for a node is that is is also creates adapters for and
+ * adapts the Node for all other registered 'create on adapt' Adapters. This
+ * other adapters are registered by registering their factories via plugin
+ * extension point.
+ */
+public class PropagatingAdapterFactoryImpl extends AbstractAdapterFactory implements PropagatingAdapterFactory {
+
+ private PropagatingAdapter adapterInstance;
+ protected List contributedFactories = null;
+
+ /**
+ * PropagatingAdapterFactory constructor comment.
+ */
+ public PropagatingAdapterFactoryImpl() {
+ this(PropagatingAdapter.class, true);
+ }
+
+ protected PropagatingAdapterFactoryImpl(Object adapterKey, boolean registerAdapters) { //,
+ // Object
+ // modelType)
+ // {
+ super(adapterKey, registerAdapters);
+ }
+
+ public void addContributedFactories(AdapterFactory factory) {
+ if (contributedFactories != null) {
+ contributedFactories.add(factory);
+ }
+
+ }
+
+ public AdapterFactory copy() {
+ PropagatingAdapterFactory clonedInstance = new PropagatingAdapterFactoryImpl(this.adapterKey, this.shouldRegisterAdapter);
+ // clone this adapters specific list of adapter factories too
+ if (contributedFactories != null) {
+ Iterator iterator = contributedFactories.iterator();
+ clonedInstance.setContributedFactories(new ArrayList());
+ while (iterator.hasNext()) {
+ AdapterFactory existingFactory = (AdapterFactory) iterator.next();
+ clonedInstance.addContributedFactories(existingFactory.copy());
+ }
+ }
+ return clonedInstance;
+ }
+
+ /**
+ * createAdapter method comment.
+ */
+ protected INodeAdapter createAdapter(INodeNotifier target) {
+ // every notifier get's one of these
+ // (and the same instance of it)
+ return getAdapterInstance();
+ }
+
+ /**
+ * Gets the adapterInstance.
+ *
+ * @return Returns a PropagatingAdapter
+ */
+ protected PropagatingAdapter getAdapterInstance() {
+ if (adapterInstance == null) {
+ adapterInstance = new PropagatingAdapterImpl();
+ if (contributedFactories != null) {
+ for (int i = 0; i < contributedFactories.size(); i++)
+ adapterInstance.addAdaptOnCreateFactory((PropagatingAdapterFactory) contributedFactories.get(i));
+ }
+ }
+ return adapterInstance;
+ }
+
+ public void release() {
+ // give the adapter instance a chance to release its factories
+ getAdapterInstance().release();
+
+ }
+
+ public void setContributedFactories(ArrayList list) {
+ contributedFactories = list;
+
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java
new file mode 100644
index 0000000000..4f0b3201f0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.propagate;
+
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.wst.sse.core.AdapterFactory;
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.PropagatingAdapter;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+
+public class PropagatingAdapterImpl implements PropagatingAdapter {
+
+ public static final Class PropagatingAdapterClass = PropagatingAdapter.class;
+ // because so many of these are created in huge file,
+ // Jeffrey Liu suggested these be done lazily, since not all
+ // models and not all nodes actually have a list of factories.
+ private List adaptOnCreateFactories = null;
+
+ /**
+ * AbstractPropagatingAdapterImpl constructor comment.
+ */
+ public PropagatingAdapterImpl() {
+ super();
+ }
+
+ protected void adaptOnCreate(XMLNode node) {
+ // give each of the factories a chance to adapt the node, if it
+ // chooses to
+ if (adaptOnCreateFactories != null) {
+ Iterator iterator = adaptOnCreateFactories.iterator();
+ while (iterator.hasNext()) {
+ AdapterFactory factory = (AdapterFactory) iterator.next();
+ factory.adapt(node);
+ }
+ }
+
+ }
+
+ /**
+ * This mechanism can be made "easier to use" later.
+ */
+ public void addAdaptOnCreateFactory(AdapterFactory factory) {
+ //adaptOnCreateFactories.add(factory);
+ getAdaptOnCreateFactories().add(factory);
+ }
+
+ /**
+ * Gets the adaptOnCreateFactories.
+ *
+ * @return Returns a List
+ */
+ public List getAdaptOnCreateFactories() {
+ if (adaptOnCreateFactories == null)
+ adaptOnCreateFactories = new ArrayList();
+ return adaptOnCreateFactories;
+ }
+
+ // protected void unadaptOnRemove(INodeNotifier node) {
+ // // give each of the factories a chance to process remove event
+ // // This is a bit out of the normal adapter pattern, but I couldn't
+ // // think of a better way to "remove" pageDirectiveWatchers, if and
+ // // when the page directive was 'removed' (edited).
+ // //
+ // Iterator iterator = adaptOnCreateFactories.iterator();
+ // while (iterator.hasNext()) {
+ // AdapterFactory factory = (AdapterFactory) iterator.next();
+ // if (factory instanceof PropagatingAdapterFactory) {
+ // ((PropagatingAdapterFactory)factory).unadapt(node);
+ // }
+ // }
+ //
+ // }
+
+ /**
+ * @see PropagatingAdapter#initializeForFactory(AdapterFactory,
+ * INodeNotifier)
+ */
+ public void initializeForFactory(AdapterFactory factory, INodeNotifier node) {
+ // we're DOM specific implimentation
+ if (node instanceof XMLNode) {
+ XMLNode xmlNode = (XMLNode) node;
+ propagateTo(xmlNode);
+ }
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type allows it
+ * to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return type.equals(PropagatingAdapterClass);
+ }
+
+ protected boolean isInteresting(Object newValue) {
+ return (newValue != null && (newValue instanceof Element || newValue instanceof Document || newValue instanceof DocumentType));
+ }
+
+ /**
+ */
+ public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ // DMW, 2002.8.10. I changed this so we only propagate to Elements ...
+ // not attributes too!
+ // I'm assuming this will help performance and memory, but don't know
+ // if anyone was depending on
+ // this being proagate to attributes.
+ if (eventType == INodeNotifier.ADD && isInteresting(newValue)) {
+ propagateTo((XMLNode) newValue);
+ }
+ // else if (eventType == INodeNotifier.CONTENT_CHANGED) {
+ // notifier.getAdapterFor(PropagatingAdapterClass);
+ // }
+ // else if (eventType == INodeNotifier.CHANGE) {
+ // }
+ // else if (eventType == INodeNotifier.REMOVE &&
+ // isInteresting(oldValue)) {
+ // unadaptOnRemove((XMLNode)oldValue);
+ // }
+ // else if (eventType == INodeNotifier.STRUCTURE_CHANGED) {
+ // }
+ }
+
+ protected void propagateTo(XMLNode node) {
+ // get adapter to ensure its created
+ node.getAdapterFor(PropagatingAdapterClass);
+ adaptOnCreate(node);
+ propagateToChildren(node);
+ }
+
+ protected void propagateToChildren(XMLNode parent) {
+ for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+ propagateTo((XMLNode) child);
+ }
+ }
+
+ /**
+ * @see PropagatingAdapter#release()
+ */
+ public void release() {
+ if (adaptOnCreateFactories != null) {
+ Iterator iterator = adaptOnCreateFactories.iterator();
+ while (iterator.hasNext()) {
+ AdapterFactory factory = (AdapterFactory) iterator.next();
+ factory.release();
+ }
+ }
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java
new file mode 100644
index 0000000000..77de14a4e7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.text;
+
+import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+
+
+public class XMLStructuredDocumentRegion extends BasicStructuredDocumentRegion implements IStructuredDocumentRegion {
+
+ public XMLStructuredDocumentRegion() {
+ super();
+ }
+
+ public String getType() {
+ String result = super.getType();
+ // normally, we want the second region as the flatnode type ... since
+ // the
+ // first one is usually just "open tag".
+ if ((result != XMLRegionContext.XML_PI_OPEN) && (getRegions().size() > 1)) {
+ result = getRegions().get(1).getType();
+ }
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java
new file mode 100644
index 0000000000..13afbc8647
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.util;
+
+import java.io.PrintStream;
+
+import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+public class DebugDocument {
+
+ public static void dump(Document document) {
+ if (document == null)
+ return;
+ System.out.println("Dump of DOM"); //$NON-NLS-1$
+
+ dump(document, System.out);
+
+ //
+ System.out.println();
+ System.out.println("= = = = = ="); //$NON-NLS-1$
+ System.out.println();
+
+ }
+
+ public static void dump(Document document, PrintStream out) {
+ Node node = document.getFirstChild();
+ while (node != null) {
+ dump(node, out);
+ node = node.getNextSibling();
+ }
+
+ }
+
+ public static void dump(Node topNode) {
+ dump(topNode, System.out);
+ }
+
+ public static void dump(Node topNode, PrintStream out) {
+ if (topNode == null)
+ return;
+ // print out this node
+ //
+ printNode(topNode, out);
+
+ // now print out its children
+ //NodeList nodes = topNode.getChildNodes();
+ //int len = nodes.getLength();
+ //for (int i = 0; i < len; i++) {
+
+ //Node node = nodes.item(i);
+ //dump(node, out);
+ //}
+ }
+
+ public static void printNode(Node topNode) {
+ printNode(topNode, System.out);
+
+ }
+
+ public static void printNode(Node topNode, PrintStream out) {
+ // print out this node
+ //
+ IStructuredDocumentRegion firstStructuredDocumentRegion = ((XMLNode) topNode).getFirstStructuredDocumentRegion();
+ IStructuredDocumentRegion lastStructuredDocumentRegion = ((XMLNode) topNode).getLastStructuredDocumentRegion();
+ if ((firstStructuredDocumentRegion == null) || (lastStructuredDocumentRegion == null)) {
+ // no text to output
+ } else {
+ int start = firstStructuredDocumentRegion.getStart();
+ int end = lastStructuredDocumentRegion.getEnd();
+
+ String outString = topNode.toString();
+ outString = org.eclipse.wst.sse.core.util.StringUtils.escape(outString);
+ out.println("[" + start + ", " + end + "]" + outString); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$
+ }
+ // now do its children
+ NodeList nodes = topNode.getChildNodes();
+ int len = nodes.getLength();
+ for (int i = 0; i < len; i++) {
+ Node childNode = nodes.item(i);
+ printNode(childNode, out);
+ }
+
+ }
+
+ public DebugDocument() {
+ super();
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java
new file mode 100644
index 0000000000..9144662bd2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.validate;
+
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.w3c.dom.Node;
+
+
+public abstract class AbstractPropagatingValidator extends ValidationComponent {
+
+ /**
+ * Constructor for AbstractPropagatingValidator.
+ */
+ public AbstractPropagatingValidator() {
+ super();
+ }
+
+ protected abstract ValidationComponent getPropagatee();
+
+ protected abstract ValidationAdapter getValidator();
+
+ /**
+ * @see com.ibm.sed.adapters.validate.ValidationAdapter#validate(IndexedRegion)
+ */
+ public void validate(IndexedRegion node) {
+ if (node == null)
+ return;
+ getValidator().validate(node);
+
+
+ Propagator.propagateToChildElements(getPropagatee(), (Node) node);
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java
new file mode 100644
index 0000000000..3cdcca5312
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.validate;
+
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.sse.core.IndexedRegion;
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+public class Propagator {
+
+ public static void propagateToChildElements(ValidationComponent validator, Node parent) {
+ if (parent == null)
+ return;
+ Class clazz = validator.getClass();
+
+ NodeList children = parent.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child == null || child.getNodeType() != Node.ELEMENT_NODE)
+ continue;
+
+ INodeNotifier notifier = (INodeNotifier) child;
+ ValidationAdapter va = (ValidationAdapter) notifier.getExistingAdapter(clazz);
+ if (va == null) {
+ notifier.addAdapter(validator);
+ va = validator;
+ }
+ va.validate((IndexedRegion) child);
+ }
+ }
+
+ /**
+ * Propagator is just a placeholder of utilities. Don't instantiate.
+ */
+ private Propagator() {
+ super();
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java
new file mode 100644
index 0000000000..797d9cbf0a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2001, 2004 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 Corporation - initial API and implementation
+ * Jens Lukowski/Innoopract - initial renaming/restructuring
+ *
+ *******************************************************************************/
+package org.eclipse.wst.xml.core.internal.validate;
+
+
+
+import org.eclipse.wst.sse.core.validate.ValidationAdapter;
+import org.eclipse.wst.sse.core.validate.ValidationReporter;
+
+public abstract class ValidationComponent implements ValidationAdapter {
+
+ protected ValidationReporter reporter = null;
+
+ /**
+ * ValidationComponent constructor comment.
+ */
+ public ValidationComponent() {
+ super();
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type allows it
+ * to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return (type == ValidationAdapter.class);
+ }
+
+ /**
+ */
+ public void notifyChanged(org.eclipse.wst.sse.core.INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ // This method will be implemented in the V2.
+ }
+
+ /**
+ */
+ public void setReporter(ValidationReporter reporter) {
+ this.reporter = reporter;
+ }
+}

Back to the top