Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'tests/org.eclipse.wst.wsdl.tests.performance/data/1000WSDLsXSDDepends/sample496.wsdl')
-rw-r--r--tests/org.eclipse.wst.wsdl.tests.performance/data/1000WSDLsXSDDepends/sample496.wsdl38
1 files changed, 0 insertions, 38 deletions
diff --git a/tests/org.eclipse.wst.wsdl.tests.performance/data/1000WSDLsXSDDepends/sample496.wsdl b/tests/org.eclipse.wst.wsdl.tests.performance/data/1000WSDLsXSDDepends/sample496.wsdl
deleted file mode 100644
index 950831dc4..000000000
--- a/tests/org.eclipse.wst.wsdl.tests.performance/data/1000WSDLsXSDDepends/sample496.wsdl
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<wsdl:definitions name="sample" targetNamespace="http://www.example.org/sample496" xmlns:tns="http://www.example.org/sample496" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
-<wsdl:types>
-<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/sample496">
-<xsd:element name="NewOperationResponse" type="xsd:string"/><xsd:element name="NewOperationRequest" type="xsd:string"/></xsd:schema>
-<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.sample.org/sample496"><xsd:import namespace="http://www.sample.org/41" schemaLocation="sample41.xsd"/>
-</xsd:schema>
-</wsdl:types>
-<wsdl:message name="NewOperationResponse">
-<wsdl:part name="NewOperationResponse" element="tns:NewOperationResponse"/>
-</wsdl:message>
-<wsdl:message name="NewOperationRequest">
-<wsdl:part name="NewOperationRequest" element="tns:NewOperationRequest"/>
-</wsdl:message>
-<wsdl:portType name="sample">
-<wsdl:operation name="NewOperation">
-<wsdl:input message="tns:NewOperationRequest"/>
-<wsdl:output message="tns:NewOperationResponse"/>
-</wsdl:operation>
-</wsdl:portType>
-<wsdl:binding name="sampleSOAP" type="tns:sample">
-<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
-<wsdl:operation name="NewOperation">
-<soap:operation soapAction="http://www.example.org/sample/NewOperation"/>
-<wsdl:input>
-<soap:body use="literal" parts=" NewOperationRequest"/>
-</wsdl:input>
-<wsdl:output>
-<soap:body use="literal" parts=" NewOperationResponse"/>
-</wsdl:output>
-</wsdl:operation>
-</wsdl:binding>
-<wsdl:service name="sample">
-<wsdl:port name="sampleSOAP" binding="tns:sampleSOAP">
-<soap:address location="http://www.example.org/"/>
-</wsdl:port>
-</wsdl:service>
-</wsdl:definitions> \ No newline at end of file

Back to the top

tat' width='100%'> -rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java70
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java54
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java150
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java123
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.java107
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java153
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java226
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java84
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java65
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java196
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.java25
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java1226
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizerConstants.java23
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLResourceEncodingDetector.java102
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java131
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.java51
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java63
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java34
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java34
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java65
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java37
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java66
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java32
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.java107
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java154
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.java36
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java103
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.java25
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java124
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.java40
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java37
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java78
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.java99
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java53
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java357
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java116
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.java21
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java775
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java27
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java198
-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
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/XMLJSPRegionContexts.java59
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/package.html8
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/EmbeddedXML.java89
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/ModelHandlerForXML.java63
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/XMLModelLoader.java95
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForEmbeddedXML.java55
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForXML.java161
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryUtil.java64
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLCatalogIdResolver.java89
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryAssociationProvider.java37
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryImpl.java38
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/parser/XMLRegionContext.java69
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/text/rules/StructuredTextPartitionerForXML.java139
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/COPYRIGHT.html100
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/DocumentRange.java39
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/Range.java434
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/RangeException.java46
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/package.html3
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/COPYRIGHT.html100
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/DocumentTraversal.java101
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeFilter.java151
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeIterator.java113
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/TreeWalker.java185
-rw-r--r--bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/package.html3
152 files changed, 34001 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.xml.core/src/.cvsignore b/bundles/org.eclipse.wst.xml.core/src/.cvsignore
new file mode 100644
index 0000000000..101c29e19d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/.cvsignore
@@ -0,0 +1 @@
+notebook.jpage
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/Logger.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/Logger.java
new file mode 100644
index 0000000000..0e727bc4b3
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/Logger.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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;
+
+import java.util.StringTokenizer;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Small convenience class to log messages to plugin's log file and also, if
+ * desired, the console. This class should only be used by classes in this
+ * plugin. Other plugins should make their own copy, with appropriate ID.
+ */
+public class Logger {
+ public static final int ERROR = IStatus.ERROR; // 4
+ public static final int ERROR_DEBUG = 200 + ERROR;
+ private static Plugin fPlugin = XMLModelPlugin.getDefault();
+ private static final String fPluginId = fPlugin.getDescriptor().getUniqueIdentifier();
+ public static final int INFO = IStatus.INFO; // 1
+ public static final int INFO_DEBUG = 200 + INFO;
+
+ public static final int OK = IStatus.OK; // 0
+
+ public static final int OK_DEBUG = 200 + OK;
+
+ private static final String TRACEFILTER_LOCATION = "/debug/tracefilter"; //$NON-NLS-1$
+ public static final int WARNING = IStatus.WARNING; // 2
+ public static final int WARNING_DEBUG = 200 + WARNING;
+
+ /**
+ * Adds message to log.
+ *
+ * @param level
+ * severity level of the message (OK, INFO, WARNING, ERROR,
+ * OK_DEBUG, INFO_DEBUG, WARNING_DEBUG, ERROR_DEBUG)
+ * @param message
+ * text to add to the log
+ * @param exception
+ * exception thrown
+ */
+ protected static void _log(int level, String message, Throwable exception) {
+ if (level == OK_DEBUG || level == INFO_DEBUG || level == WARNING_DEBUG || level == ERROR_DEBUG) {
+ if (!isDebugging())
+ return;
+ }
+
+ int severity = IStatus.OK;
+ switch (level) {
+ case INFO_DEBUG :
+ case INFO :
+ severity = IStatus.INFO;
+ break;
+ case WARNING_DEBUG :
+ case WARNING :
+ severity = IStatus.WARNING;
+ break;
+ case ERROR_DEBUG :
+ case ERROR :
+ severity = IStatus.ERROR;
+ }
+ message = (message != null) ? message : "null"; //$NON-NLS-1$
+ Status statusObj = new Status(severity, fPluginId, severity, message, exception);
+ fPlugin.getLog().log(statusObj);
+ }
+
+ /**
+ * Prints message to log if category matches /debug/tracefilter option.
+ *
+ * @param message
+ * text to print
+ * @param category
+ * category of the message, to be compared with
+ * /debug/tracefilter
+ */
+ protected static void _trace(String category, String message, Throwable exception) {
+ if (isTracing(category)) {
+ message = (message != null) ? message : "null"; //$NON-NLS-1$
+ Status statusObj = new Status(IStatus.OK, fPluginId, IStatus.OK, message, exception);
+ fPlugin.getLog().log(statusObj);
+ }
+ }
+
+ /**
+ * @return true if the plugin for this logger is debugging
+ */
+ public static boolean isDebugging() {
+ return fPlugin.isDebugging();
+ }
+
+ /**
+ * Determines if currently tracing a category
+ *
+ * @param category
+ * @return true if tracing category, false otherwise
+ */
+ public static boolean isTracing(String category) {
+ if (!isDebugging())
+ return false;
+
+ String traceFilter = Platform.getDebugOption(fPluginId + TRACEFILTER_LOCATION);
+ if (traceFilter != null) {
+ StringTokenizer tokenizer = new StringTokenizer(traceFilter, ","); //$NON-NLS-1$
+ while (tokenizer.hasMoreTokens()) {
+ String cat = tokenizer.nextToken().trim();
+ if (category.equals(cat)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static void log(int level, String message) {
+ _log(level, message, null);
+ }
+
+ public static void log(int level, String message, Throwable exception) {
+ _log(level, message, exception);
+ }
+
+ public static void logException(String message, Throwable exception) {
+ _log(ERROR, message, exception);
+ }
+
+ public static void logException(Throwable exception) {
+ _log(ERROR, exception.getMessage(), exception);
+ }
+
+ public static void trace(String category, String message) {
+ _trace(category, message, null);
+ }
+
+ public static void traceException(String category, String message, Throwable exception) {
+ _trace(category, message, exception);
+ }
+
+ public static void traceException(String category, Throwable exception) {
+ _trace(category, exception.getMessage(), exception);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/NameValidator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/NameValidator.java
new file mode 100644
index 0000000000..a0d564be80
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/NameValidator.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;
+
+import java.io.Reader;
+
+import org.eclipse.wst.xml.core.internal.parser.XML10Names;
+
+
+
+public final class NameValidator {
+
+ private static XML10Names charChecker = new XML10Names((Reader) null);
+
+ public synchronized static final boolean isValid(String name) {
+
+ return charChecker.isValidXML10Name(name);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLModelPlugin.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLModelPlugin.java
new file mode 100644
index 0000000000..c531d0baf7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLModelPlugin.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 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;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.wst.common.encoding.CommonEncodingPreferenceNames;
+import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames;
+
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class XMLModelPlugin extends Plugin {
+ //The shared instance.
+ private static XMLModelPlugin plugin;
+
+ /**
+ * Returns the shared instance.
+ */
+ public static XMLModelPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns the string from the plugin's resource bundle, or 'key' if not
+ * found.
+ */
+ public static String getResourceString(String key) {
+ ResourceBundle bundle = XMLModelPlugin.getDefault().getResourceBundle();
+ try {
+ return bundle.getString(key);
+ } catch (MissingResourceException e) {
+ return key;
+ }
+ }
+
+ /**
+ * Returns the workspace instance.
+ */
+ public static IWorkspace getWorkspace() {
+ return ResourcesPlugin.getWorkspace();
+ }
+
+ //Resource bundle.
+ private ResourceBundle resourceBundle;
+
+ /**
+ * The constructor.
+ */
+ public XMLModelPlugin(IPluginDescriptor descriptor) {
+ super(descriptor);
+ plugin = this;
+ try {
+ resourceBundle = ResourceBundle.getBundle("org.eclipse.wst.xml.core.XmlPluginResources"); //$NON-NLS-1$
+ } catch (MissingResourceException x) {
+ resourceBundle = null;
+ }
+ }
+
+ /**
+ * Returns the plugin's resource bundle,
+ */
+ public ResourceBundle getResourceBundle() {
+ return resourceBundle;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.Plugin#initializeDefaultPluginPreferences()
+ */
+ protected void initializeDefaultPluginPreferences() {
+ super.initializeDefaultPluginPreferences();
+ Preferences prefs = getDefault().getPluginPreferences();
+ // set model preference defaults
+ prefs.setDefault(CommonModelPreferenceNames.CLEANUP_TAG_NAME_CASE, CommonModelPreferenceNames.ASIS);
+ prefs.setDefault(CommonModelPreferenceNames.CLEANUP_ATTR_NAME_CASE, CommonModelPreferenceNames.ASIS);
+ prefs.setDefault(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS, true);
+ prefs.setDefault(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS, true);
+ prefs.setDefault(CommonModelPreferenceNames.INSERT_MISSING_TAGS, true);
+ prefs.setDefault(CommonModelPreferenceNames.QUOTE_ATTR_VALUES, true);
+ prefs.setDefault(CommonModelPreferenceNames.FORMAT_SOURCE, true);
+ prefs.setDefault(CommonModelPreferenceNames.CONVERT_EOL_CODES, false);
+
+ prefs.setDefault(CommonEncodingPreferenceNames.INPUT_CODESET, ""); //$NON-NLS-1$
+ prefs.setDefault(CommonEncodingPreferenceNames.OUTPUT_CODESET, CommonModelPreferenceNames.UTF_8);
+ prefs.setDefault(CommonEncodingPreferenceNames.END_OF_LINE_CODE, ""); //$NON-NLS-1$
+
+ prefs.setDefault(CommonModelPreferenceNames.TAB_WIDTH, 4);
+
+ prefs.setDefault(CommonModelPreferenceNames.FORMATTING_SUPPORTED, true);
+ prefs.setDefault(CommonModelPreferenceNames.LINE_WIDTH, 72);
+ prefs.setDefault(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS, false);
+ prefs.setDefault(CommonModelPreferenceNames.INDENT_USING_TABS, true);
+ prefs.setDefault(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES, false);
+
+ prefs.setDefault(CommonModelPreferenceNames.PREFERRED_MARKUP_CASE_SUPPORTED, false);
+ prefs.setDefault(CommonModelPreferenceNames.TAG_NAME_CASE, CommonModelPreferenceNames.LOWER);
+ prefs.setDefault(CommonModelPreferenceNames.ATTR_NAME_CASE, CommonModelPreferenceNames.LOWER);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLPreferenceNames.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLPreferenceNames.java
new file mode 100644
index 0000000000..4df06f069f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLPreferenceNames.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;
+
+
+
+public interface XMLPreferenceNames {
+ String CLEANUP_ATTR_NAME_CASE = "cleanupAttrNameCase";//$NON-NLS-1$
+ String CLEANUP_EOL_CODE = "cleanupEOLCode";//$NON-NLS-1$
+ // cleanup preference names
+ String CLEANUP_TAG_NAME_CASE = "cleanupTagNameCase";//$NON-NLS-1$
+ String CONVERT_EOL_CODES = "convertEOLCodes";//$NON-NLS-1$
+ String FORMAT_SOURCE = "formatSource";//$NON-NLS-1$
+ String INSERT_MISSING_TAGS = "insertMissingTags";//$NON-NLS-1$
+
+ // others
+ String LAST_ACTIVE_PAGE = "lastActivePage";//$NON-NLS-1$
+ String QUOTE_ATTR_VALUES = "quoteAttrValues";//$NON-NLS-1$
+
+ /*
+ * not used for now // highlighting types String COMMENT_BORDER =
+ * "commentBorder";//$NON-NLS-1$ String COMMENT_TEXT =
+ * "commentText";//$NON-NLS-1$ String CDATA_BORDER =
+ * "cdataBorder";//$NON-NLS-1$ String CDATA_TEXT =
+ * "cdataText";//$NON-NLS-1$ String PI_BORDER = "piBorder";//$NON-NLS-1$
+ * String PI_CONTENT = "piContent";//$NON-NLS-1$ String TAG_BORDER =
+ * "tagBorder";//$NON-NLS-1$ String TAG_NAME = "tagName";//$NON-NLS-1$
+ * String TAG_ATTRIBUTE_NAME = "tagAttributeName";//$NON-NLS-1$ String
+ * TAG_ATTRIBUTE_VALUE = "tagAttributeValue";//$NON-NLS-1$ String
+ * DECL_BORDER = "declBoder";//$NON-NLS-1$ String DOCTYPE_NAME =
+ * "doctypeName";//$NON-NLS-1$ String DOCTYPE_EXTERNAL_ID =
+ * "doctypeExternalId";//$NON-NLS-1$ String DOCTYPE_EXTERNAL_ID_PUBREF =
+ * "doctypeExternalPubref";//$NON-NLS-1$ String DOCTYPE_EXTERNAL_ID_SYSREF =
+ * "doctypeExtrenalSysref";//$NON-NLS-1$ String XML_CONTENT =
+ * "xmlContent";//$NON-NLS-1$ // highlighting preferences String COMMA =
+ * ",";//$NON-NLS-1$ String COLOR = "color";//$NON-NLS-1$ String NAME =
+ * "name";//$NON-NLS-1$ String FOREGROUND = "foreground";//$NON-NLS-1$
+ * String BACKGROUND = "background";//$NON-NLS-1$ String BOLD =
+ * "bold";//$NON-NLS-1$ String ITALIC = "italic";//$NON-NLS-1$
+ */
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/delegates/XMLTaskTagSeeker.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/delegates/XMLTaskTagSeeker.java
new file mode 100644
index 0000000000..a9bba3b35f
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/delegates/XMLTaskTagSeeker.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.builder.delegates;
+
+import org.eclipse.wst.sse.core.participants.TaskTagSeeker;
+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 XMLTaskTagSeeker extends TaskTagSeeker {
+
+ /**
+ *
+ */
+ public XMLTaskTagSeeker() {
+ super();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.participants.TaskTagSeeker#isCommentRegion(org.eclipse.wst.sse.core.text.IStructuredDocumentRegion,
+ * org.eclipse.wst.sse.core.text.ITextRegion)
+ */
+ protected boolean isCommentRegion(IStructuredDocumentRegion region, ITextRegion textRegion) {
+ return textRegion.getType().equals(XMLRegionContext.XML_COMMENT_TEXT);
+
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/participants/XMLTaskTagParticipant.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/participants/XMLTaskTagParticipant.java
new file mode 100644
index 0000000000..0c7774ddd9
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/participants/XMLTaskTagParticipant.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.builder.participants;
+
+import org.eclipse.wst.sse.core.participants.TaskTagParticipant;
+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 XMLTaskTagParticipant extends TaskTagParticipant {
+ protected boolean isCommentRegion(IStructuredDocumentRegion region, ITextRegion textRegion) {
+ return textRegion.getType().equals(XMLRegionContext.XML_COMMENT_TEXT);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/CleanupProcessorXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/CleanupProcessorXML.java
new file mode 100644
index 0000000000..6e69a59cde
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/CleanupProcessorXML.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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.cleanup;
+
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier;
+import org.eclipse.wst.sse.core.cleanup.AbstractStructuredCleanupProcessor;
+import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupHandler;
+import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupPreferences;
+import org.eclipse.wst.sse.core.cleanup.StructuredCleanupPreferences;
+import org.eclipse.wst.sse.core.format.IStructuredFormatProcessor;
+import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames;
+import org.eclipse.wst.xml.core.XMLModelPlugin;
+import org.eclipse.wst.xml.core.format.FormatProcessorXML;
+import org.w3c.dom.Node;
+
+
+public class CleanupProcessorXML extends AbstractStructuredCleanupProcessor {
+ protected IStructuredCleanupPreferences fCleanupPreferences = null;
+
+ protected IStructuredCleanupHandler getCleanupHandler(Node node) {
+ short nodeType = node.getNodeType();
+ IStructuredCleanupHandler cleanupHandler = null;
+ switch (nodeType) {
+ case Node.ELEMENT_NODE : {
+ cleanupHandler = new ElementNodeCleanupHandler();
+ break;
+ }
+ case Node.TEXT_NODE : {
+ cleanupHandler = new NodeCleanupHandler();
+ break;
+ }
+ default : {
+ cleanupHandler = new NodeCleanupHandler();
+ }
+ }
+
+ // init CleanupPreferences
+ cleanupHandler.setCleanupPreferences(getCleanupPreferences());
+
+ return cleanupHandler;
+ }
+
+ public IStructuredCleanupPreferences getCleanupPreferences() {
+ if (fCleanupPreferences == null) {
+ fCleanupPreferences = new StructuredCleanupPreferences();
+
+ Preferences preferences = getModelPreferences();
+ if (preferences != null) {
+ fCleanupPreferences.setTagNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_TAG_NAME_CASE));
+ fCleanupPreferences.setAttrNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_ATTR_NAME_CASE));
+ fCleanupPreferences.setCompressEmptyElementTags(preferences.getBoolean(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS));
+ fCleanupPreferences.setInsertRequiredAttrs(preferences.getBoolean(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS));
+ fCleanupPreferences.setInsertMissingTags(preferences.getBoolean(CommonModelPreferenceNames.INSERT_MISSING_TAGS));
+ fCleanupPreferences.setQuoteAttrValues(preferences.getBoolean(CommonModelPreferenceNames.QUOTE_ATTR_VALUES));
+ fCleanupPreferences.setFormatSource(preferences.getBoolean(CommonModelPreferenceNames.FORMAT_SOURCE));
+ fCleanupPreferences.setConvertEOLCodes(preferences.getBoolean(CommonModelPreferenceNames.CONVERT_EOL_CODES));
+ fCleanupPreferences.setEOLCode(preferences.getString(CommonModelPreferenceNames.CLEANUP_EOL_CODE));
+ }
+ }
+
+ return fCleanupPreferences;
+ }
+
+ protected String getContentType() {
+ return IContentTypeIdentifier.ContentTypeID_SSEXML;
+ }
+
+ protected IStructuredFormatProcessor getFormatProcessor() {
+ return new FormatProcessorXML();
+ }
+
+ protected Preferences getModelPreferences() {
+ return XMLModelPlugin.getDefault().getPluginPreferences();
+ }
+
+ protected void refreshCleanupPreferences() {
+ fCleanupPreferences = null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/ElementNodeCleanupHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/ElementNodeCleanupHandler.java
new file mode 100644
index 0000000000..39f4e31b3a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/ElementNodeCleanupHandler.java
@@ -0,0 +1,556 @@
+/*******************************************************************************
+ * 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.cleanup;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.text.edits.MultiTextEdit;
+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.common.contentmodel.modelquery.ModelQuery;
+import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupHandler;
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+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.sse.core.util.StringUtils;
+import org.eclipse.wst.xml.core.document.XMLAttr;
+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.XMLModel;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+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;
+
+
+public class ElementNodeCleanupHandler extends NodeCleanupHandler {
+ protected static final char DOUBLE_QUOTE = '\"'; //$NON-NLS-1$
+ protected static final String DOUBLE_QUOTES = "\"\""; //$NON-NLS-1$
+ protected static final String EMPTY_TAG_CLOSE = "/>"; //$NON-NLS-1$
+ protected static final String END_TAG_OPEN = "</"; //$NON-NLS-1$
+ protected static final char SINGLE_QUOTE = '\''; //$NON-NLS-1$
+ protected static final String SINGLE_QUOTES = "''"; //$NON-NLS-1$
+
+ /** Non-NLS strings */
+ protected static final String START_TAG_OPEN = "<"; //$NON-NLS-1$
+ protected static final String TAG_CLOSE = ">"; //$NON-NLS-1$
+
+ public Node cleanup(Node node) {
+ Node newNode = cleanupChildren(node);
+ XMLNode renamedNode = newNode instanceof XMLNode ? (XMLNode) newNode : null;
+
+ // call quoteAttrValue() first so it will close any unclosed attr
+ // quoteAttrValue() will return the new start tag if there is a
+ // structure change
+ renamedNode = quoteAttrValue(renamedNode);
+
+ // insert tag close if missing
+ // if node is not comment tag
+ // and not implicit tag
+ if (!isCommentTag(renamedNode) && !isImplicitTag(renamedNode)) {
+ XMLModel structuredModel = renamedNode.getModel();
+
+ // save start offset before insertTagClose()
+ // or else renamedNode.getStartOffset() will be zero if
+ // renamedNode replaced by insertTagClose()
+ int startTagStartOffset = renamedNode.getStartOffset();
+
+ // for start tag
+ IStructuredDocumentRegion startTagStructuredDocumentRegion = renamedNode.getStartStructuredDocumentRegion();
+ insertTagClose(structuredModel, startTagStructuredDocumentRegion);
+
+ // update renamedNode and startTagStructuredDocumentRegion after
+ // insertTagClose()
+ renamedNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset);
+ startTagStructuredDocumentRegion = renamedNode.getStartStructuredDocumentRegion();
+
+ // for end tag
+ IStructuredDocumentRegion endTagStructuredDocumentRegion = renamedNode.getEndStructuredDocumentRegion();
+ if (endTagStructuredDocumentRegion != startTagStructuredDocumentRegion)
+ insertTagClose(structuredModel, endTagStructuredDocumentRegion);
+ }
+
+ // call insertMissingTags() next, it will generate implicit tags if
+ // there are any
+ // insertMissingTags() will return the new missing start tag if one is
+ // missing
+ renamedNode = insertMissingTags(renamedNode);
+
+ renamedNode = compressEmptyElementTag(renamedNode);
+
+ renamedNode = insertRequiredAttrs(renamedNode);
+
+ return renamedNode;
+ }
+
+ protected Node cleanupChildren(Node node) {
+ Node parentNode = node;
+
+ if (node != null) {
+ Node childNode = node.getFirstChild();
+ while (childNode != null) {
+ // get cleanup handler
+ IStructuredCleanupHandler cleanupHandler = getCleanupHandler(childNode);
+
+ // cleanup each child
+ childNode = cleanupHandler.cleanup(childNode);
+
+ // get new parent node
+ parentNode = (XMLNode) childNode.getParentNode();
+
+ // get next child node
+ childNode = (XMLNode) childNode.getNextSibling();
+ }
+ }
+
+ return parentNode;
+ }
+
+ private XMLNode compressEmptyElementTag(XMLNode node) {
+ boolean compressEmptyElementTags = getCleanupPreferences().getCompressEmptyElementTags();
+ XMLNode newNode = node;
+
+ IStructuredDocumentRegion startTagStructuredDocumentRegion = newNode.getFirstStructuredDocumentRegion();
+ IStructuredDocumentRegion endTagStructuredDocumentRegion = newNode.getLastStructuredDocumentRegion();
+
+ if (compressEmptyElementTags && startTagStructuredDocumentRegion != endTagStructuredDocumentRegion && startTagStructuredDocumentRegion != null) {
+ ITextRegionList regions = startTagStructuredDocumentRegion.getRegions();
+ ITextRegion lastRegion = regions.get(regions.size() - 1);
+ // format children and end tag if not empty element tag
+ if (lastRegion.getType() != XMLRegionContext.XML_EMPTY_TAG_CLOSE) {
+ NodeList childNodes = newNode.getChildNodes();
+ if (childNodes == null || childNodes.getLength() == 0 || (childNodes.getLength() == 1 && (childNodes.item(0)).getNodeType() == Node.TEXT_NODE && ((childNodes.item(0)).getNodeValue().trim().length() == 0))) {
+ XMLModel structuredModel = newNode.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+
+ int startTagStartOffset = newNode.getStartOffset();
+ int offset = endTagStructuredDocumentRegion.getStart();
+ int length = endTagStructuredDocumentRegion.getLength();
+ structuredDocument.replaceText(structuredDocument, offset, length, ""); //$NON-NLS-1$
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save
+
+ offset = startTagStructuredDocumentRegion.getStart() + lastRegion.getStart();
+ structuredDocument.replaceText(structuredDocument, offset, 0, "/"); //$NON-NLS-1$
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save
+ }
+ }
+ }
+
+ return newNode;
+ }
+
+ protected IStructuredCleanupHandler getCleanupHandler(Node node) {
+ short nodeType = node.getNodeType();
+ IStructuredCleanupHandler cleanupHandler = null;
+ switch (nodeType) {
+ case org.w3c.dom.Node.ELEMENT_NODE : {
+ cleanupHandler = new ElementNodeCleanupHandler();
+ break;
+ }
+ case org.w3c.dom.Node.TEXT_NODE : {
+ cleanupHandler = new NodeCleanupHandler();
+ break;
+ }
+ default : {
+ cleanupHandler = new NodeCleanupHandler();
+ }
+ }
+
+ // init CleanupPreferences
+ cleanupHandler.setCleanupPreferences(getCleanupPreferences());
+
+ return cleanupHandler;
+ }
+
+
+ protected ModelQuery getModelQuery(Node node) {
+ if (node.getNodeType() == Node.DOCUMENT_NODE) {
+ return ModelQueryUtil.getModelQuery((Document) node);
+ } else {
+ return ModelQueryUtil.getModelQuery(node.getOwnerDocument());
+ }
+ }
+
+ protected List getRequiredAttrs(Node node) {
+ List result = new ArrayList();
+
+ ModelQuery modelQuery = getModelQuery(node);
+ if (modelQuery != null) {
+ CMElementDeclaration elementDecl = modelQuery.getCMElementDeclaration((Element) node);
+ if (elementDecl != null) {
+ CMNamedNodeMap attrMap = elementDecl.getAttributes();
+ Iterator it = attrMap.iterator();
+ CMAttributeDeclaration attr = null;
+ while (it.hasNext()) {
+ attr = (CMAttributeDeclaration) it.next();
+ if (attr.getUsage() == CMAttributeDeclaration.REQUIRED) {
+ result.add(attr);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private XMLNode insertEndTag(XMLNode node) {
+ XMLNode newNode = node;
+ XMLElement element = (XMLElement) node;
+ if (element.isCommentTag())
+ return node; // do nothing
+
+ int startTagStartOffset = node.getStartOffset();
+ XMLModel structuredModel = node.getModel();
+
+ if (isEmptyElement(element)) {
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion();
+ ITextRegionList regions = startStructuredDocumentRegion.getRegions();
+ ITextRegion lastRegion = regions.get(regions.size() - 1);
+ structuredDocument.replaceText(structuredDocument, startStructuredDocumentRegion.getStartOffset(lastRegion), lastRegion.getLength(), EMPTY_TAG_CLOSE);
+
+ if (regions.size() > 1) {
+ ITextRegion regionBeforeTagClose = regions.get(regions.size() - 1 - 1);
+
+ // insert a space separator before tag close if the previous
+ // region does not have extra spaces
+ if (regionBeforeTagClose.getTextLength() == regionBeforeTagClose.getLength())
+ structuredDocument.replaceText(structuredDocument, startStructuredDocumentRegion.getStartOffset(lastRegion), 0, " "); //$NON-NLS-1$
+ }
+ } else {
+ String tagName = node.getNodeName();
+ String endTag = END_TAG_OPEN.concat(tagName).concat(TAG_CLOSE);
+
+ XMLNode lastChild = (XMLNode) node.getLastChild();
+ int endTagStartOffset = 0;
+ if (lastChild != null)
+ // if this node has children, insert the end tag after the
+ // last child
+ endTagStartOffset = lastChild.getEndOffset();
+ else
+ // if this node does not has children, insert the end tag
+ // after the start tag
+ endTagStartOffset = node.getEndOffset();
+
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ structuredDocument.replaceText(structuredDocument, endTagStartOffset, 0, endTag);
+ }
+
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save
+ // new
+ // node
+
+ return newNode;
+ }
+
+ private XMLNode insertMissingTags(XMLNode node) {
+ boolean insertMissingTags = getCleanupPreferences().getInsertMissingTags();
+ XMLNode newNode = node;
+
+ if (insertMissingTags) {
+ IStructuredDocumentRegion startTagStructuredDocumentRegion = node.getStartStructuredDocumentRegion();
+ if (startTagStructuredDocumentRegion == null) {
+ // implicit start tag; generate tag for it
+ newNode = insertStartTag(node);
+ startTagStructuredDocumentRegion = newNode.getStartStructuredDocumentRegion();
+ }
+
+ IStructuredDocumentRegion endTagStructuredDocumentRegion = newNode.getEndStructuredDocumentRegion();
+ ITextRegionList startStructuredDocumentRegionRegions = startTagStructuredDocumentRegion.getRegions();
+ if (startTagStructuredDocumentRegion != null && startStructuredDocumentRegionRegions != null && (startStructuredDocumentRegionRegions.get(startStructuredDocumentRegionRegions.size() - 1)).getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) {
+
+ } else {
+ if (startTagStructuredDocumentRegion == null) {
+ // start tag missing
+ if (isStartTagRequired(newNode))
+ newNode = insertStartTag(newNode);
+ } else if (endTagStructuredDocumentRegion == null) {
+ // end tag missing
+ if (isEndTagRequired(newNode))
+ newNode = insertEndTag(newNode);
+ }
+ }
+ }
+
+ return newNode;
+ }
+
+ private XMLNode insertRequiredAttrs(XMLNode node) {
+ boolean insertRequiredAttrs = getCleanupPreferences().getInsertRequiredAttrs();
+ XMLNode newNode = node;
+
+ if (insertRequiredAttrs) {
+ List requiredAttrs = getRequiredAttrs(newNode);
+ if (requiredAttrs.size() > 0) {
+ NamedNodeMap currentAttrs = node.getAttributes();
+ List insertAttrs = new ArrayList();
+ if (currentAttrs.getLength() == 0)
+ insertAttrs.addAll(requiredAttrs);
+ else {
+ for (int i = 0; i < requiredAttrs.size(); i++) {
+ String requiredAttrName = ((CMAttributeDeclaration) requiredAttrs.get(i)).getAttrName();
+ boolean found = false;
+ for (int j = 0; j < currentAttrs.getLength(); j++) {
+ String currentAttrName = currentAttrs.item(j).getNodeName();
+ if (requiredAttrName.compareToIgnoreCase(currentAttrName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ insertAttrs.add(requiredAttrs.get(i));
+ }
+ }
+ if (insertAttrs.size() > 0) {
+ IStructuredDocumentRegion startStructuredDocumentRegion = newNode.getStartStructuredDocumentRegion();
+ int index = startStructuredDocumentRegion.getEndOffset();
+ ITextRegion lastRegion = startStructuredDocumentRegion.getLastRegion();
+ if (lastRegion.getType() == XMLRegionContext.XML_TAG_CLOSE) {
+ index--;
+ lastRegion = startStructuredDocumentRegion.getRegionAtCharacterOffset(index - 1);
+ } else if (lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) {
+ index = index - 2;
+ lastRegion = startStructuredDocumentRegion.getRegionAtCharacterOffset(index - 1);
+ }
+ MultiTextEdit multiTextEdit = new MultiTextEdit();
+ try {
+ for (int i = insertAttrs.size() - 1; i >= 0; i--) {
+ CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) insertAttrs.get(i);
+ String requiredAttributeName = attrDecl.getAttrName();
+ String defaultValue = attrDecl.getDefaultValue();
+ if (defaultValue == null)
+ defaultValue = ""; //$NON-NLS-1$
+ String nameAndDefaultValue = " "; //$NON-NLS-1$
+ if (i == 0 && lastRegion.getLength() > lastRegion.getTextLength())
+ nameAndDefaultValue = ""; //$NON-NLS-1$
+ nameAndDefaultValue += requiredAttributeName + "=\"" + defaultValue + "\""; //$NON-NLS-1$ //$NON-NLS-2$
+ multiTextEdit.addChild(new InsertEdit(index, nameAndDefaultValue));
+ // BUG3381: MultiTextEdit applies all child
+ // TextEdit's basing on offsets
+ // in the document before the first TextEdit, not
+ // after each
+ // child TextEdit. Therefore, do not need to
+ // advance the index.
+ //index += nameAndDefaultValue.length();
+ }
+ multiTextEdit.apply(newNode.getStructuredDocument());
+ } catch (BadLocationException e) {
+ throw new SourceEditingRuntimeException(e);
+ }
+ }
+ }
+ }
+
+ return newNode;
+ }
+
+ private XMLNode insertStartTag(XMLNode node) {
+ XMLNode newNode = node;
+
+ if (isCommentTag(node))
+ return node; // do nothing
+
+ String tagName = node.getNodeName();
+ String startTag = START_TAG_OPEN.concat(tagName).concat(TAG_CLOSE);
+ int startTagStartOffset = node.getStartOffset();
+
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ structuredDocument.replaceText(structuredDocument, startTagStartOffset, 0, startTag);
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save
+ // new
+ // node
+
+ return newNode;
+ }
+
+ private void insertTagClose(XMLModel structuredModel, IStructuredDocumentRegion flatNode) {
+ if (flatNode != null) {
+ ITextRegionList flatnodeRegions = flatNode.getRegions();
+ if (flatnodeRegions != null) {
+ ITextRegion lastRegion = flatnodeRegions.get(flatnodeRegions.size() - 1);
+ if (lastRegion != null) {
+ String regionType = lastRegion.getType();
+ if ((regionType != XMLRegionContext.XML_EMPTY_TAG_CLOSE) && (regionType != XMLRegionContext.XML_TAG_CLOSE)) {
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+
+ // insert ">" after lastRegion of flatNode
+ // as in "<a</a>" if flatNode is for start tag, or in
+ // "<a></a" if flatNode is for end tag
+ structuredDocument.replaceText(structuredDocument, flatNode.getTextEndOffset(lastRegion), 0, ">"); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param renamedNode
+ * @return
+ */
+ private boolean isCommentTag(Node renamedNode) {
+ boolean result = false;
+ if (renamedNode instanceof XMLElement) {
+ XMLElement element = (XMLElement) renamedNode;
+ result = element.isCommentTag();
+ }
+ return result;
+ }
+
+ private boolean isEmptyElement(XMLElement element) {
+ Document document = element.getOwnerDocument();
+ if (document == null)
+ // undefined tag, return default
+ return false;
+
+ ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document);
+ if (modelQuery == null)
+ // undefined tag, return default
+ return false;
+
+ CMElementDeclaration decl = modelQuery.getCMElementDeclaration(element);
+ if (decl == null)
+ // undefined tag, return default
+ return false;
+
+ return (decl.getContentType() == CMElementDeclaration.EMPTY);
+ }
+
+ private boolean isEndTagRequired(XMLNode node) {
+ if (node == null)
+ return false;
+ return node.isContainer();
+ }
+
+ /**
+ * A tag is implicit if it has not corresponding region in document.
+ *
+ * @param renamedNode
+ * @return
+ */
+ private boolean isImplicitTag(XMLNode renamedNode) {
+ return renamedNode.getStartStructuredDocumentRegion() == null;
+ }
+
+ /**
+ * The end tags of HTML EMPTY content type, such as IMG, and HTML
+ * undefined tags are parsed separately from the start tags. So inserting
+ * the missing start tag is useless and even harmful.
+ */
+ private boolean isStartTagRequired(XMLNode node) {
+ if (node == null)
+ return false;
+ return node.isContainer();
+ }
+
+ private boolean isXMLType(XMLModel structuredModel) {
+ boolean result = false;
+
+ if (structuredModel != null && structuredModel != null) {
+ XMLDocument document = structuredModel.getDocument();
+
+ if (document != null)
+ result = document.isXMLType();
+ }
+
+ return result;
+ }
+
+ private XMLNode quoteAttrValue(XMLNode node) {
+ XMLNode newNode = node;
+ //XMLElement element = (XMLElement) node;
+ if (isCommentTag(node))
+ return node; // do nothing
+
+ boolean quoteAttrValues = getCleanupPreferences().getQuoteAttrValues();
+
+ if (quoteAttrValues) {
+ NamedNodeMap attributes = newNode.getAttributes();
+ if (attributes != null) {
+ int attributesLength = attributes.getLength();
+ XMLGenerator generator = node.getModel().getGenerator();
+
+ for (int i = 0; i < attributesLength; i++) {
+ attributes = newNode.getAttributes();
+ attributesLength = attributes.getLength();
+ XMLAttr eachAttr = (XMLAttr) attributes.item(i);
+ //ITextRegion oldAttrValueRegion =
+ // eachAttr.getValueRegion();
+ String oldAttrValue = eachAttr.getValueRegionText();
+ if (oldAttrValue == null) {
+ XMLModel structuredModel = node.getModel();
+ if (isXMLType(structuredModel)) {
+ String newAttrValue = "\"" + eachAttr.getNameRegionText() + "\""; //$NON-NLS-1$ //$NON-NLS-2$
+
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ if (eachAttr.getEqualRegion() != null)
+ // equal region exists
+ structuredDocument.replaceText(structuredDocument, eachAttr.getEndOffset(), 0, newAttrValue);
+ else
+ // no equal region
+ structuredDocument.replaceText(structuredDocument, eachAttr.getNameRegionTextEndOffset(), 0, "=".concat(newAttrValue)); //$NON-NLS-1$
+ newNode = (XMLNode) structuredModel.getIndexedRegion(node.getStartOffset()); // save
+ // new
+ // node
+ }
+ } else {
+ //String oldAttrValue = oldAttrValueRegion.getText();
+ char quote = StringUtils.isQuoted(oldAttrValue) ? oldAttrValue.charAt(0) : DOUBLE_QUOTE;
+ String newAttrValue = generator.generateAttrValue(eachAttr, quote);
+
+ // There is a problem in
+ // StructuredDocumentRegionUtil.getAttrValue(ITextRegion)
+ // when the region is instanceof ContextRegion.
+ // Workaround for now...
+ if (oldAttrValue.length() == 1) {
+ char firstChar = oldAttrValue.charAt(0);
+ if (firstChar == SINGLE_QUOTE)
+ newAttrValue = SINGLE_QUOTES;
+ else if (firstChar == DOUBLE_QUOTE)
+ newAttrValue = DOUBLE_QUOTES;
+ }
+
+ if (newAttrValue != null) {
+ if (newAttrValue.compareTo(oldAttrValue) != 0) {
+ int attrValueStartOffset = eachAttr.getValueRegionStartOffset();
+ int attrValueLength = oldAttrValue.length();
+ int startTagStartOffset = node.getStartOffset();
+
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ structuredDocument.replaceText(structuredDocument, attrValueStartOffset, attrValueLength, newAttrValue);
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save
+ // new
+ // node
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return newNode;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java
new file mode 100644
index 0000000000..ffdb1977d4
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.cleanup;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupHandler;
+import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupPreferences;
+import org.eclipse.wst.sse.core.cleanup.StructuredCleanupPreferences;
+import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames;
+import org.eclipse.wst.xml.core.XMLModelPlugin;
+import org.w3c.dom.Node;
+
+
+public class NodeCleanupHandler implements IStructuredCleanupHandler {
+
+ protected IStructuredCleanupPreferences fCleanupPreferences = null;
+ protected IProgressMonitor fProgressMonitor = null;
+
+ /**
+ * @see com.ibm.sed.partitionCleanup.CleanupHandler#cleanup(com.ibm.sed.model.xml.XMLNode)
+ */
+ public Node cleanup(Node node) {
+
+ return node;
+ }
+
+ /**
+ * @see com.ibm.sed.partitionCleanup.CleanupHandler#getCleanupPreferences()
+ */
+ public IStructuredCleanupPreferences getCleanupPreferences() {
+ if (fCleanupPreferences == null) {
+ fCleanupPreferences = new StructuredCleanupPreferences();
+
+ Preferences preferences = getModelPreferences();
+ if (preferences != null) {
+ fCleanupPreferences.setTagNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_TAG_NAME_CASE));
+ fCleanupPreferences.setAttrNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_ATTR_NAME_CASE));
+ fCleanupPreferences.setCompressEmptyElementTags(preferences.getBoolean(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS));
+ fCleanupPreferences.setInsertRequiredAttrs(preferences.getBoolean(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS));
+ fCleanupPreferences.setInsertMissingTags(preferences.getBoolean(CommonModelPreferenceNames.INSERT_MISSING_TAGS));
+ fCleanupPreferences.setQuoteAttrValues(preferences.getBoolean(CommonModelPreferenceNames.QUOTE_ATTR_VALUES));
+ fCleanupPreferences.setFormatSource(preferences.getBoolean(CommonModelPreferenceNames.FORMAT_SOURCE));
+ fCleanupPreferences.setConvertEOLCodes(preferences.getBoolean(CommonModelPreferenceNames.CONVERT_EOL_CODES));
+ fCleanupPreferences.setEOLCode(preferences.getString(CommonModelPreferenceNames.CLEANUP_EOL_CODE));
+ }
+ }
+
+ return fCleanupPreferences;
+ }
+
+ protected Preferences getModelPreferences() {
+ return XMLModelPlugin.getDefault().getPluginPreferences();
+ }
+
+ public void setCleanupPreferences(IStructuredCleanupPreferences cleanupPreferences) {
+
+ fCleanupPreferences = cleanupPreferences;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java
new file mode 100644
index 0000000000..6bae47a150
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.cleanup;
+
+import org.eclipse.core.runtime.Preferences;
+
+/**
+ * @deprecated renamed to IStructuredCleanupPreferences
+ *
+ * TODO will delete in C5
+ */
+public interface XMLCleanupPreferences {
+
+ int getAttrNameCase();
+
+ boolean getConvertEOLCodes();
+
+ String getEOLCode();
+
+ boolean getFormatSource();
+
+ boolean getInsertMissingTags();
+
+ boolean getQuoteAttrValues();
+
+ int getTagNameCase();
+
+ void setAttrNameCase(int attrNameCase);
+
+ void setConvertEOLCodes(boolean convertEOLCodes);
+
+ void setEOLCode(String EOLCode);
+
+ void setFormatSource(boolean formatSource);
+
+ void setInsertMissingTags(boolean insertMissingTags);
+
+ //void setPreferenceStore(IPreferenceStore preferenceStore);
+ void setPreferences(Preferences preferences);
+
+ void setQuoteAttrValues(boolean quoteAttrValues);
+
+ void setTagNameCase(int tagNameCase);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java
new file mode 100644
index 0000000000..6dccbc1302
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * 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.cleanup;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.wst.sse.core.IModelManagerPlugin;
+import org.eclipse.wst.xml.core.XMLPreferenceNames;
+
+
+/**
+ * @deprecated renamed to StructuredCleanupPreferences
+ *
+ * TODO will delete in C5
+ */
+public class XMLCleanupPreferencesImpl implements XMLCleanupPreferences {
+
+ private static XMLCleanupPreferencesImpl fInstance;
+
+ public synchronized static XMLCleanupPreferencesImpl getInstance() {
+
+ // added for one method in CleanupDialog ... may be better way
+ if (fInstance == null) {
+ fInstance = new XMLCleanupPreferencesImpl();
+ }
+ return fInstance;
+ }
+
+ private int fAttrNameCase;
+ private boolean fConvertEOLCodes;
+ private String fEOLCode;
+ private boolean fFormatSource;
+ private boolean fInsertMissingTags;
+ //private IPreferenceStore fPreferenceStore = null;
+ private Preferences fPreferences = null;
+ private boolean fQuoteAttrValues;
+ private int fTagNameCase;
+
+ public int getAttrNameCase() {
+
+ return fAttrNameCase;
+ }
+
+ public boolean getConvertEOLCodes() {
+
+ return fConvertEOLCodes;
+ }
+
+ public String getEOLCode() {
+
+ return fEOLCode;
+ }
+
+ public boolean getFormatSource() {
+
+ return fFormatSource;
+ }
+
+ public boolean getInsertMissingTags() {
+
+ return fInsertMissingTags;
+ }
+
+ private IModelManagerPlugin getModelManagerPlugin() {
+
+ IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID);
+ return plugin;
+ }
+
+ public Preferences getPreferences() {
+
+ if (fPreferences == null) {
+ fPreferences = getModelManagerPlugin().getPluginPreferences();
+ }
+ return fPreferences;
+ }
+
+ public boolean getQuoteAttrValues() {
+
+ return fQuoteAttrValues;
+ }
+
+ public int getTagNameCase() {
+
+ return fTagNameCase;
+ }
+
+ public void setAttrNameCase(int attrNameCase) {
+
+ fAttrNameCase = attrNameCase;
+ }
+
+ public void setConvertEOLCodes(boolean convertEOLCodes) {
+
+ fConvertEOLCodes = convertEOLCodes;
+ }
+
+ public void setEOLCode(String EOLCode) {
+
+ fEOLCode = EOLCode;
+ }
+
+ public void setFormatSource(boolean formatSource) {
+
+ fFormatSource = formatSource;
+ }
+
+ public void setInsertMissingTags(boolean insertMissingTags) {
+
+ fInsertMissingTags = insertMissingTags;
+ }
+
+ public void setPreferences(Preferences prefs) {
+
+ fPreferences = prefs;
+ updateOptions();
+ }
+
+ public void setQuoteAttrValues(boolean quoteAttrValues) {
+
+ fQuoteAttrValues = quoteAttrValues;
+ }
+
+ public void setTagNameCase(int tagNameCase) {
+
+ fTagNameCase = tagNameCase;
+ }
+
+ protected void updateOptions() {
+
+ Preferences p = getPreferences();
+ fTagNameCase = p.getInt(XMLPreferenceNames.CLEANUP_TAG_NAME_CASE);
+ fAttrNameCase = p.getInt(XMLPreferenceNames.CLEANUP_ATTR_NAME_CASE);
+ fInsertMissingTags = p.getBoolean(XMLPreferenceNames.INSERT_MISSING_TAGS);
+ fQuoteAttrValues = p.getBoolean(XMLPreferenceNames.QUOTE_ATTR_VALUES);
+ fFormatSource = p.getBoolean(XMLPreferenceNames.FORMAT_SOURCE);
+ fConvertEOLCodes = p.getBoolean(XMLPreferenceNames.CONVERT_EOL_CODES);
+ fEOLCode = p.getString(XMLPreferenceNames.CLEANUP_EOL_CODE);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java
new file mode 100644
index 0000000000..ae18f47946
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * 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.commentelement;
+
+
+
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.wst.sse.core.INodeNotifier;
+import org.eclipse.wst.xml.core.commentelement.impl.CommentElementConfiguration;
+import org.eclipse.wst.xml.core.document.TagAdapter;
+import org.eclipse.wst.xml.core.document.XMLElement;
+
+
+/**
+ */
+public class CommentElementAdapter implements TagAdapter {
+ private CommentElementConfiguration fConfiguration;
+
+ private boolean fEndTag;
+ private CommentElementHandler fHandler;
+
+ public CommentElementAdapter(boolean isEndTag, CommentElementHandler handler) {
+ fEndTag = isEndTag;
+ fHandler = handler;
+ }
+
+ private String generateCommentClose(XMLElement element) {
+ return (element.isJSPTag()) ? "--%>" : "-->"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private String generateCommentOpen(XMLElement element) {
+ return (element.isJSPTag()) ? "<%--" : "<!--"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private CommentElementConfiguration getConfiguration() {
+ return fConfiguration;
+ }
+
+ /**
+ * @see com.ibm.sed.model.xml.TagAdapter#getEndTag(XMLElement)
+ */
+ public String getEndTag(XMLElement element) {
+ String content = fHandler.generateEndTagContent(element);
+ if (content == null) {
+ return null;
+ }
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append(generateCommentOpen(element));
+ buffer.append(content);
+ buffer.append(generateCommentClose(element));
+
+ return buffer.toString();
+ }
+
+ public String getHandlerID() {
+ return getConfiguration().getHandlerID();
+ }
+
+ public IPluginDescriptor getHandlerPluginDescriptor() {
+ return fConfiguration.getHandlerPluginDescriptor();
+ }
+
+ public String getProperty(String name) {
+ return getConfiguration().getProperty(name);
+ }
+
+ /**
+ * @see com.ibm.sed.model.xml.TagAdapter#getStartTag(XMLElement)
+ */
+ public String getStartTag(XMLElement element) {
+ String content = fHandler.generateStartTagContent(element);
+ if (content == null) {
+ return null;
+ }
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append(generateCommentOpen(element));
+ buffer.append(content);
+ buffer.append(generateCommentClose(element));
+
+ return buffer.toString();
+ }
+
+ /**
+ * @see com.ibm.sed.model.INodeAdapter#isAdapterForType(Object)
+ */
+ public boolean isAdapterForType(Object type) {
+ return (type == CommentElementAdapter.class || type == TagAdapter.class);
+ }
+
+ public boolean isContainer() {
+ return (!fHandler.isEmpty());
+ }
+
+ /**
+ * @see com.ibm.sed.model.xml.TagAdapter#isEndTag()
+ */
+ public boolean isEndTag() {
+ return fEndTag;
+ }
+
+ /**
+ * @see com.ibm.sed.model.INodeAdapter#notifyChanged(INodeNotifier, int,
+ * Object, Object, Object, int)
+ */
+ public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ }
+
+ public void setConfiguration(CommentElementConfiguration configuration) {
+ fConfiguration = configuration;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.java
new file mode 100644
index 0000000000..b5eae28068
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.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.commentelement;
+
+
+
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ */
+public interface CommentElementHandler {
+ /**
+ * This method is called when the prefix of the comment content matches
+ * the string specified in &lt;startswith prefix=""/&gt; in plugin
+ * extension. Comment content is parsed and new DOM element is created in
+ * this method. Implementor has to do following:
+ * <li>For start tag :
+ * <ul>
+ * <li>parse comment content and create new element instance.</li>
+ * </ul>
+ * </li>
+ * <li>For end tag :
+ * <ul>
+ * <li>parse comment content and create new element instance.</li>
+ * <li>make isEndTag flag true.</li>
+ * <li>Parser framework searches mached start tag element instance after
+ * this createElement call, and new instance is just thrown away.</li>
+ * </ul>
+ * </li>
+ * <li>For empty tag :
+ * <ul>
+ * <li>parse comment content and create new element instance.</li>
+ * <li>make isEndTag flag true.</li>
+ * </ul>
+ * </li>
+ *
+ * @param document
+ * parent DOM document
+ * @param data
+ * comment content. comment prefix (&lt;!-- or &lt;%--), suffix
+ * (--&gt; or --%&gt;), and surrounding spaces are trimmed.
+ * @param isJSPTag
+ * true if the comment is JSP style comment. This information
+ * may be required by handler when the handler accepts both XML
+ * style and JSP style comment (namely,
+ * commenttype=&quot;both&quot; in plugin.xml).
+ * @return comment element instance if the comment content is rightly
+ * parsed. if parse failed, returns null.
+ */
+ Element createElement(Document document, String data, boolean isJSPTag);
+
+ /**
+ * This method generates the source text of the end tag for the passed
+ * element. Do not generate comment prefix (&lt;!-- or &lt;%--) and suffix
+ * (--&gt; or --%&gt;). XMLGenerator uses this method to generate XML/HTML
+ * source for a comment element.
+ *
+ * @param element
+ * the comment element
+ * @return generated tag string
+ */
+ String generateEndTagContent(XMLElement element);
+
+ /**
+ * This method generates the source text of the start tag for the passed
+ * element. Do not generate comment prefix (&lt;!-- or &lt;%--) and suffix
+ * (--&gt; or --%&gt;). XMLGenerator uses this method to generate XML/HTML
+ * source for a comment element.
+ *
+ * @param element
+ * the comment element
+ * @return generated tag string
+ */
+ String generateStartTagContent(XMLElement element);
+
+ /**
+ *
+ * @param element
+ * the element
+ * @return boolean whether the element is comment element or not
+ */
+ boolean isCommentElement(XMLElement element);
+
+ /**
+ *
+ * @return boolean whether this element can have children or not
+ */
+ boolean isEmpty();
+
+ /**
+ * @return String
+ */
+ // String getElementPrefix();
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java
new file mode 100644
index 0000000000..98efac0f7d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * 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.commentelement.impl;
+
+
+
+import org.eclipse.wst.xml.core.commentelement.CommentElementHandler;
+import org.eclipse.wst.xml.core.commentelement.util.CommentElementFactory;
+import org.eclipse.wst.xml.core.commentelement.util.TagScanner;
+import org.eclipse.wst.xml.core.document.XMLAttr;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.eclipse.wst.xml.core.document.XMLGenerator;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+
+/**
+ */
+class BasicCommentElementHandler implements CommentElementHandler {
+
+ private String elementName;
+ private boolean isEmpty;
+
+ public BasicCommentElementHandler(String elementName, boolean isEmpty) {
+ super();
+ this.elementName = elementName;
+ this.isEmpty = isEmpty;
+ }
+
+ /**
+ * @see com.ibm.sed.model.commentelement.CommentElementHandler#createElement(Document,
+ * String, boolean)
+ */
+ public Element createElement(Document document, String data, boolean isJSPTag) {
+ Element element = null;
+ String str = data.trim();
+ CommentElementFactory factory = new CommentElementFactory(document, isJSPTag, this);
+ if (str.charAt(0) == '/') { // end tag
+ TagScanner scanner = new TagScanner(str, 1); // skip '/'
+ String name = scanner.nextName();
+ if (name.equals(elementName)) {
+ element = factory.create(name, CommentElementFactory.IS_END);
+ }
+ } else { // start tag
+ TagScanner scanner = new TagScanner(str, 0);
+ String name = scanner.nextName();
+ if (name.equals(elementName)) {
+ element = factory.create(name, (isEmpty) ? CommentElementFactory.IS_EMPTY : CommentElementFactory.IS_START);
+ // set attributes
+ String attrName = scanner.nextName();
+ while (attrName != null) {
+ String attrValue = scanner.nextValue();
+ Attr attr = document.createAttribute(attrName);
+ if (attr != null) {
+ if (attrValue != null)
+ ((XMLAttr) attr).setValueSource(attrValue);
+ element.setAttributeNode(attr);
+ }
+ attrName = scanner.nextName();
+ }
+ }
+ }
+ return element;
+ }
+
+ /**
+ * @see com.ibm.sed.model.commentelement.CommentElementHandler#getEndTag(XMLElement)
+ */
+ public String generateEndTagContent(XMLElement element) {
+ if (isEmpty) {
+ return null;
+ }
+ XMLGenerator generator = element.getModel().getGenerator();
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append(" /"); //$NON-NLS-1$
+ String tagName = generator.generateTagName(element);
+ if (tagName != null) {
+ buffer.append(tagName);
+ }
+ buffer.append(' ');
+
+ return buffer.toString();
+ }
+
+ /**
+ * @see com.ibm.sed.model.commentelement.CommentElementHandler#getStartTag(XMLElement)
+ */
+ public String generateStartTagContent(XMLElement element) {
+ XMLGenerator generator = element.getModel().getGenerator();
+ StringBuffer buffer = new StringBuffer();
+
+ buffer.append(' ');
+ String tagName = generator.generateTagName(element);
+ if (tagName != null) {
+ buffer.append(tagName);
+ }
+
+ NamedNodeMap attributes = element.getAttributes();
+ int length = attributes.getLength();
+ for (int i = 0; i < length; i++) {
+ Attr attr = (Attr) attributes.item(i);
+ if (attr == null) {
+ continue;
+ }
+ buffer.append(' ');
+ String attrName = generator.generateAttrName(attr);
+ if (attrName != null) {
+ buffer.append(attrName);
+ }
+ String attrValue = generator.generateAttrValue(attr);
+ if (attrValue != null) {
+ // attr name only for HTML boolean and JSP
+ buffer.append('=');
+ buffer.append(attrValue);
+ }
+ }
+
+ buffer.append(' ');
+
+ return buffer.toString();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.model.commentelement.CommentElementHandler#isCommentElement(com.ibm.sed.model.xml.XMLElement)
+ */
+ public boolean isCommentElement(XMLElement element) {
+ return (element != null && element.getTagName().equals(elementName)) ? true : false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.ibm.sed.model.commentelement.CommentElementHandler#isEmpty()
+ */
+ public boolean isEmpty() {
+ return isEmpty;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java
new file mode 100644
index 0000000000..d4aac41461
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * 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.commentelement.impl;
+
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPluginDescriptor;
+import org.eclipse.wst.xml.core.Logger;
+import org.eclipse.wst.xml.core.commentelement.CommentElementAdapter;
+import org.eclipse.wst.xml.core.commentelement.CommentElementHandler;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ */
+public class CommentElementConfiguration {
+ private Map fAttributes = null;
+ private boolean fCustom;
+ private IConfigurationElement fElement = null;
+
+ private boolean fEmpty;
+ private CommentElementHandler fHandler = null;
+ private String fID = null;
+ private boolean fJSPComment;
+ private String[] fPrefix = null;
+ private boolean fXMLComment;
+
+ CommentElementConfiguration() {
+ super();
+ }
+
+ CommentElementConfiguration(IConfigurationElement element) {
+ super();
+ fElement = element;
+ fCustom = (element.getName().equalsIgnoreCase("handler-custom")) ? true : false; //$NON-NLS-1$
+
+ fillAttributes(element);
+
+ fXMLComment = fJSPComment = false;
+ String commentType = getProperty("commenttype"); //$NON-NLS-1$
+ if (commentType.equalsIgnoreCase("xml")) { //$NON-NLS-1$
+ fXMLComment = true;
+ } else if (commentType.equalsIgnoreCase("jsp")) { //$NON-NLS-1$
+ fJSPComment = true;
+ } else if (commentType.equalsIgnoreCase("both")) { //$NON-NLS-1$
+ fXMLComment = fJSPComment = true;
+ }
+ String empty = getProperty("isempty"); //$NON-NLS-1$
+ fEmpty = (empty != null && !empty.equals("false")) ? true : false; //$NON-NLS-1$
+ }
+
+ public boolean acceptJSPComment() {
+ return fJSPComment;
+ }
+
+ public boolean acceptXMLComment() {
+ return fXMLComment;
+ }
+
+ public Element createElement(Document document, String data, boolean isJSPTag) {
+ XMLElement element = (XMLElement) getHandler().createElement(document, data, isJSPTag);
+ if (element != null) {
+ CommentElementAdapter adapter = (CommentElementAdapter) element.getAdapterFor(CommentElementAdapter.class);
+ if (adapter != null) {
+ adapter.setConfiguration(this);
+ }
+ }
+ return element;
+ }
+
+ private void fillAttributes(IConfigurationElement element) {
+ if (fAttributes == null) {
+ fAttributes = new HashMap();
+ } else {
+ fAttributes.clear();
+ }
+ String[] names = element.getAttributeNames();
+ if (names == null) {
+ return;
+ }
+ int length = names.length;
+ for (int i = 0; i < length; i++) {
+ String name = names[i];
+ fAttributes.put(name.toLowerCase(), element.getAttribute(name));
+ }
+ }
+
+ public CommentElementHandler getHandler() {
+ if (fHandler == null) {
+ if (fElement != null) {
+ try {
+ if (isCustom()) {
+ fHandler = (CommentElementHandler) fElement.createExecutableExtension("class"); //$NON-NLS-1$
+ } else {
+ String elementName = getProperty("elementname"); //$NON-NLS-1$
+ fHandler = new BasicCommentElementHandler(elementName, fEmpty);
+ }
+ // ((AbstractCommentElementHandler)fHandler).setElementPrefix(fElement.getAttribute("prefix"));
+ } catch (Exception e) {
+ // catch and log (and ignore) ANY exception created
+ // by executable extension.
+ Logger.logException(e);
+ fHandler = null;
+ }
+ }
+ if (fHandler == null) {
+ fHandler = new CommentElementHandler() {
+ public Element createElement(Document document, String data, boolean isJSPTag) {
+ return null;
+ }
+
+ public String generateEndTagContent(XMLElement element) {
+ return null;
+ }
+
+ public String generateStartTagContent(XMLElement element) {
+ return null;
+ }
+
+ public String getElementPrefix() {
+ return null;
+ }
+
+ public boolean isCommentElement(XMLElement element) {
+ return false;
+ }
+
+ public boolean isEmpty() {
+ return false;
+ }
+ };
+ }
+ }
+ return fHandler;
+ }
+
+ public String getHandlerID() {
+ if (fID == null) {
+ fID = getProperty("id"); //$NON-NLS-1$
+ if (fID == null) {
+ if (isCustom()) {
+ fID = getProperty("class"); //$NON-NLS-1$
+ } else {
+ StringBuffer buf = new StringBuffer();
+ buf.append(getHandlerPluginDescriptor().getUniqueIdentifier());
+ buf.append('.');
+ buf.append(getProperty("elementname")); //$NON-NLS-1$
+ fID = buf.toString();
+ }
+ }
+ }
+ return fID;
+ }
+
+ public IPluginDescriptor getHandlerPluginDescriptor() {
+ return fElement.getDeclaringExtension().getDeclaringPluginDescriptor();
+ }
+
+ public String[] getPrefix() {
+ if (fPrefix == null) {
+ if (fElement != null) {
+ if (isCustom()) { // custom
+ IConfigurationElement[] prefixes = fElement.getChildren("startwith"); //$NON-NLS-1$
+ if (prefixes != null) {
+ fPrefix = new String[prefixes.length];
+ for (int i = 0; i < prefixes.length; i++) {
+ fPrefix[i] = prefixes[i].getAttribute("prefix"); //$NON-NLS-1$
+ }
+ }
+ } else { // basic
+ String name = getProperty("elementname"); //$NON-NLS-1$
+ if (name != null) {
+ if (isEmpty()) {
+ fPrefix = new String[1];
+ fPrefix[0] = name;
+ } else {
+ fPrefix = new String[2];
+ fPrefix[0] = name;
+ fPrefix[1] = '/' + name;
+ }
+ }
+ }
+ }
+ }
+ if (fPrefix == null) {
+ fPrefix = new String[1];
+ fPrefix[0] = ""; //$NON-NLS-1$
+ }
+ return fPrefix;
+ }
+
+ public String getProperty(String name) {
+ return (fAttributes != null) ? (String) fAttributes.get(name) : null;
+ }
+
+ private boolean isCustom() {
+ return fCustom;
+ }
+
+ private boolean isEmpty() {
+ return fEmpty;
+ }
+
+ void setupCommentElement(XMLElement element) {
+ element.setCommentTag(true);
+ CommentElementAdapter adapter = new CommentElementAdapter(false, fHandler);
+ adapter.setConfiguration(this);
+ element.addAdapter(adapter);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java
new file mode 100644
index 0000000000..3245298479
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.commentelement.impl;
+
+
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPluginRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.wst.xml.core.commentelement.CommentElementHandler;
+import org.eclipse.wst.xml.core.document.XMLElement;
+
+
+/**
+ */
+public class CommentElementRegistry {
+
+ private static CommentElementRegistry fInstance = null;
+
+ public synchronized static CommentElementRegistry getInstance() {
+ if (fInstance == null) {
+ fInstance = new CommentElementRegistry();
+ }
+ return fInstance;
+ }
+
+ private String EXTENSION_POINT_ID = "commentElementHandler"; //$NON-NLS-1$
+ private CommentElementConfiguration[] fConfigurations = null;
+
+ private String PLUGIN_ID = "org.eclipse.wst.sse.core"; //$NON-NLS-1$
+
+ /**
+ * Constructor for CommentElementRegistry.
+ */
+ private CommentElementRegistry() {
+ super();
+ }
+
+ public CommentElementConfiguration[] getConfigurations() {
+ if (fConfigurations == null) {
+ IPluginRegistry pluginRegistry = Platform.getPluginRegistry();
+ IExtensionPoint point = pluginRegistry.getExtensionPoint(PLUGIN_ID, EXTENSION_POINT_ID);
+ if (point != null) {
+ IConfigurationElement[] elements = point.getConfigurationElements();
+ fConfigurations = new CommentElementConfiguration[elements.length];
+ for (int i = 0; i < elements.length; i++) {
+ fConfigurations[i] = new CommentElementConfiguration(elements[i]);
+ }
+ }
+ if (fConfigurations == null) {
+ fConfigurations = new CommentElementConfiguration[0];
+ }
+ }
+ return fConfigurations;
+ }
+
+ public boolean setupCommentElement(XMLElement element) {
+ CommentElementConfiguration configurations[] = getConfigurations();
+ int length = configurations.length;
+ for (int i = 0; i < length; i++) {
+ CommentElementConfiguration conf = configurations[i];
+ boolean isJSP = element.isJSPTag();
+ if (isJSP && conf.acceptJSPComment() || !isJSP && conf.acceptXMLComment()) {
+ CommentElementHandler handler = conf.getHandler();
+ if (handler.isCommentElement(element)) {
+ conf.setupCommentElement(element);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java
new file mode 100644
index 0000000000..2ae4c84734
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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.commentelement.util;
+
+
+
+import org.eclipse.wst.xml.core.commentelement.CommentElementAdapter;
+import org.eclipse.wst.xml.core.commentelement.CommentElementHandler;
+import org.eclipse.wst.xml.core.document.XMLElement;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+
+/**
+ */
+public class CommentElementFactory {
+ public static final int IS_EMPTY = 4866;
+ public static final int IS_END = 1808;
+
+ public static final int IS_START = 28011;
+
+ private Document fDocument;
+ private CommentElementHandler fHandler;
+ private boolean fJSPTag;
+
+ /**
+ * Constructor for CommentElementFactory.
+ */
+ private CommentElementFactory() {
+ super();
+ }
+
+ public CommentElementFactory(Document document, boolean isJSPTag, CommentElementHandler handler) {
+ super();
+ fDocument = document;
+ fJSPTag = isJSPTag;
+ fHandler = handler;
+ }
+
+ public Element create(String name, int nodeType) {
+ XMLElement element = (XMLElement) fDocument.createElement(name);
+ if (element == null)
+ return null;
+ element.setCommentTag(true);
+ if (nodeType == IS_EMPTY) {
+ element.setEmptyTag(true);
+ }
+ element.setJSPTag(fJSPTag);
+
+ CommentElementAdapter adapter = new CommentElementAdapter((nodeType == IS_END), fHandler);
+ element.addAdapter(adapter);
+
+ return element;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java
new file mode 100644
index 0000000000..a74fe0bb77
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java
@@ -0,0 +1,196 @@
+/*******************************************************************************
+ * 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.commentelement.util;
+
+
+
+/**
+ */
+public class TagScanner {
+
+ /**
+ */
+ private static boolean isEqual(char c) {
+ return (c == '=');
+ }
+
+ /**
+ */
+ private static boolean isQuote(char c) {
+ return (c == '"' || c == '\'');
+ }
+
+ /**
+ */
+ private static boolean isSpace(char c) {
+ return Character.isWhitespace(c);
+ }
+
+ private int length = 0;
+ private int memOffset = 0;
+ private int offset = 0;
+ private boolean oneLine = false;
+
+ private String tag = null;
+
+ /**
+ */
+ public TagScanner(String tag, int offset) {
+ super();
+
+ this.tag = tag;
+ this.offset = offset;
+ this.memOffset = -1;
+ if (tag != null)
+ this.length = tag.length();
+ }
+
+ /**
+ */
+ public TagScanner(String tag, int offset, boolean oneLine) {
+ this(tag, offset);
+
+ this.oneLine = oneLine;
+ }
+
+ /**
+ */
+ public int getNextOffset() {
+ int i;
+ char c;
+ for (i = offset; i < length; i++) {
+ c = tag.charAt(i);
+ if (isEnd(c))
+ break;
+ if (isQuote(c)) {
+ i++;
+ break;
+ }
+ if (!isSpace(c) && !isEqual(c))
+ break;
+ }
+ return i;
+ }
+
+ /**
+ */
+ public int getOffset() {
+ return this.memOffset;
+ }
+
+ /**
+ */
+ private final boolean isEnd(char c) {
+ return (this.oneLine && (c == '\r' || c == '\n'));
+ }
+
+ /**
+ */
+ public boolean isNewLine() {
+ if (oneLine)
+ return false;
+ char c;
+ for (int i = memOffset - 1; 0 <= i; i--) {
+ c = tag.charAt(i);
+ if (c == '\r' || c == '\n')
+ return true;
+ if (!isSpace(c))
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ */
+ private char nextChar() {
+ for (; this.offset < this.length; this.offset++) {
+ char c = this.tag.charAt(this.offset);
+ if (isEnd(c))
+ break;
+ if (!isSpace(c))
+ return c;
+ }
+ return 0;
+ }
+
+ /**
+ */
+ public String nextName() {
+ if (this.tag == null)
+ return null;
+ if (this.offset >= this.length)
+ return null;
+
+ if (nextChar() == 0)
+ return null;
+
+ int nameOffset = this.offset;
+ for (; this.offset < this.length; this.offset++) {
+ char c = this.tag.charAt(this.offset);
+ if (isEnd(c) || isSpace(c))
+ break;
+ if (isEqual(c) && this.offset > nameOffset)
+ break;
+ }
+ if (this.offset == nameOffset)
+ return null;
+
+ this.memOffset = nameOffset;
+ return this.tag.substring(nameOffset, this.offset);
+ }
+
+ /**
+ */
+ public String nextValue() {
+ if (this.tag == null)
+ return null;
+ if (this.offset >= this.length)
+ return null;
+
+ char seperator = nextChar();
+ if (!isEqual(seperator))
+ return null;
+ this.offset++; // skip '='
+ char quote = nextChar();
+ if (quote == 0)
+ return null;
+ if (isQuote(quote))
+ this.offset++;
+ else
+ quote = 0;
+
+ int valueOffset = this.offset;
+ for (; this.offset < this.length; this.offset++) {
+ char c = this.tag.charAt(this.offset);
+ if (isEnd(c)) {
+ quote = 0;
+ break;
+ }
+ if (quote == 0) {
+ if (isSpace(c))
+ break;
+ } else {
+ if (c == quote)
+ break;
+ }
+ }
+ int valueEnd = this.offset;
+ if (quote != 0 && this.offset < this.length)
+ this.offset++;
+ if (valueEnd == valueOffset)
+ return null;
+
+ this.memOffset = valueOffset;
+ return this.tag.substring(valueOffset, valueEnd);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.java
new file mode 100644
index 0000000000..a78089e004
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.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.contenttype;
+
+import org.eclipse.core.runtime.content.ITextContentDescriber;
+import org.eclipse.wst.common.encoding.AbstractContentDescriber;
+import org.eclipse.wst.common.encoding.IResourceCharsetDetector;
+
+
+public class ContentDescriberForXML extends AbstractContentDescriber implements ITextContentDescriber {
+ protected IResourceCharsetDetector getDetector() {
+ return new XMLResourceEncodingDetector();
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java
new file mode 100644
index 0000000000..35ca57cf57
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java
@@ -0,0 +1,1226 @@
+/*******************************************************************************
+ * 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.contenttype;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.eclipse.wst.common.encoding.IntStack;
+import org.eclipse.wst.xml.core.internal.contenttype.EncodingParserConstants;
+import org.eclipse.wst.xml.core.internal.contenttype.HeadParserToken;
+
+
+
+/**
+ * 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"; //$NON-NLS-2$//$NON-NLS-3$
+
+ /**
+ * 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 */
+ // future_TODO: remove from skeleton
+ // 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
+ */
+ // future_TODO: remove from skeleton
+ //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 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 */
+ // future_TODO: remove from skeleton
+ //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
+ */
+ // future_TODO: remove from skeleton
+ //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/contenttype/XMLHeadTokenizerConstants.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizerConstants.java
new file mode 100644
index 0000000000..1153d5fdfa
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizerConstants.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * 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.contenttype;
+
+import org.eclipse.wst.common.encoding.EncodingParserConstants;;
+
+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/contenttype/XMLResourceEncodingDetector.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLResourceEncodingDetector.java
new file mode 100644
index 0000000000..0d9d0c75d1
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLResourceEncodingDetector.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * 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.contenttype;
+
+import java.io.IOException;
+
+import org.eclipse.wst.common.encoding.AbstractResourceEncodingDetector;
+import org.eclipse.wst.common.encoding.EncodingMemento;
+import org.eclipse.wst.common.encoding.EncodingParserConstants;
+import org.eclipse.wst.common.encoding.IResourceCharsetDetector;
+import org.eclipse.wst.xml.core.internal.contenttype.HeadParserToken;
+
+
+public class XMLResourceEncodingDetector extends AbstractResourceEncodingDetector implements IResourceCharsetDetector {
+ private XMLHeadTokenizer fTokenizer;
+
+ private boolean canHandleAsUnicodeStream(String tokenType) {
+ boolean canHandleAsUnicodeStream = false;
+ if (tokenType == EncodingParserConstants.UTF83ByteBOM) {
+ canHandleAsUnicodeStream = true;
+ String enc = "UTF-8"; //$NON-NLS-1$
+ createEncodingMemento(enc, EncodingMemento.DETECTED_STANDARD_UNICODE_BYTES);
+ fEncodingMemento.setUTF83ByteBOMUsed(true);
+ }
+
+ else if (tokenType == EncodingParserConstants.UTF16BE) {
+ canHandleAsUnicodeStream = true;
+ String enc = "UTF-16BE"; //$NON-NLS-1$
+ createEncodingMemento(enc, EncodingMemento.DETECTED_STANDARD_UNICODE_BYTES);
+ } else if (tokenType == EncodingParserConstants.UTF16LE) {
+ canHandleAsUnicodeStream = true;
+ String enc = "UTF-16"; //$NON-NLS-1$
+ createEncodingMemento(enc, EncodingMemento.DETECTED_STANDARD_UNICODE_BYTES);
+ }
+ return canHandleAsUnicodeStream;
+ }
+
+ public String getSpecDefaultEncoding() {
+ // by default, UTF-8 as per XML spec
+ final String enc = "UTF-8"; //$NON-NLS-1$
+ return enc;
+ }
+
+ /**
+ * @return Returns the tokenizer.
+ */
+ private XMLHeadTokenizer getTokenizer() {
+ // TODO: need to work on 'reset' in tokenizer, so new instance isn't
+ // always needed
+ //if (fTokenizer == null) {
+ fTokenizer = new XMLHeadTokenizer();
+ //}
+ return fTokenizer;
+ }
+
+ private boolean isLegalString(String valueTokenType) {
+ if (valueTokenType == null)
+ return false;
+ else
+ return valueTokenType.equals(EncodingParserConstants.StringValue) || valueTokenType.equals(EncodingParserConstants.UnDelimitedStringValue) || valueTokenType.equals(EncodingParserConstants.InvalidTerminatedStringValue) || valueTokenType.equals(EncodingParserConstants.InvalidTermintatedUnDelimitedStringValue);
+ }
+
+ protected 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)) {
+ // side effect of canHandle is to create appropriate memento
+ } else {
+ if (tokenType == XMLHeadTokenizerConstants.XMLDelEncoding) {
+ if (tokenizer.hasMoreTokens()) {
+ token = tokenizer.getNextToken();
+ tokenType = token.getType();
+ if (isLegalString(tokenType)) {
+ String enc = token.getText();
+ if (enc != null && enc.length() > 0) {
+ createEncodingMemento(enc, EncodingMemento.FOUND_ENCODING_IN_CONTENT);
+ }
+
+ }
+ }
+ }
+ }
+ } while (tokenizer.hasMoreTokens());
+
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java
new file mode 100644
index 0000000000..0561e4c0f2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * 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.document;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.wst.common.encoding.CodedReaderCreator;
+import org.eclipse.wst.common.encoding.EncodingMemento;
+import org.eclipse.wst.common.encoding.EncodingRule;
+import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector;
+import org.eclipse.wst.sse.core.document.IDocumentLoader;
+import org.eclipse.wst.sse.core.document.IDocumentLoaderForFileBuffers;
+import org.eclipse.wst.sse.core.document.IEncodedDocument;
+import org.eclipse.wst.sse.core.document.StructuredDocumentLoader;
+import org.eclipse.wst.xml.core.encoding.XMLDocumentCharsetDetector;
+import org.eclipse.wst.xml.core.internal.filebuffers.DocumentFactoryForXML;
+import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML;
+
+
+
+public class DocumentLoaderForXML extends StructuredDocumentLoader implements IDocumentLoader, IDocumentLoaderForFileBuffers {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.document.IDocumentLoader#createNewStructuredDocument()
+ */
+ public IEncodedDocument createNewStructuredDocument() {
+ DocumentFactoryForXML factory = new DocumentFactoryForXML();
+ IEncodedDocument document = (IEncodedDocument) factory.createDocument();
+ return document;
+ }
+
+ public IEncodedDocument createNewStructuredDocument(Reader reader) throws UnsupportedEncodingException, IOException {
+ IEncodedDocument structuredDocument = createNewStructuredDocument();
+ StringBuffer allText = readInputStream(reader);
+ structuredDocument.set(allText.toString());
+ return structuredDocument;
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.document.IDocumentLoader#createNewStructuredDocument(java.lang.String,
+ * java.io.InputStream)
+ */
+ public IEncodedDocument createNewStructuredDocument(String filename, InputStream inputStream) throws IOException {
+ return createNewStructuredDocument(filename, inputStream, EncodingRule.CONTENT_BASED);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.document.IDocumentLoader#createNewStructuredDocument(java.lang.String,
+ * java.io.InputStream, com.ibm.encoding.resource.EncodingRule)
+ */
+ public IEncodedDocument createNewStructuredDocument(String filename, InputStream inputStream, EncodingRule encodingRule) throws IOException {
+ if (filename == null && inputStream == null) {
+ throw new IllegalArgumentException("can not have both null filename and inputstream"); //$NON-NLS-1$
+ }
+ CodedReaderCreator codedReaderCreator = new CodedReaderCreator();
+ Reader fullPreparedReader = null;
+ IEncodedDocument structuredDocument = createNewStructuredDocument();
+ try {
+ codedReaderCreator.set(filename, inputStream);
+ codedReaderCreator.setEncodingRule(encodingRule);
+ EncodingMemento encodingMemento = codedReaderCreator.getEncodingMemento();
+ fullPreparedReader = codedReaderCreator.getCodedReader();
+ structuredDocument.setEncodingMemento(encodingMemento);
+ StringBuffer allText = readInputStream(fullPreparedReader);
+ structuredDocument.set(allText.toString());
+ } catch (CoreException e) {
+ // impossible in this context
+ throw new Error(e);
+ } finally {
+ if (fullPreparedReader != null) {
+ fullPreparedReader.close();
+ }
+ }
+
+ return structuredDocument;
+ }
+
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.document.IDocumentLoader#getDefaultDocumentPartitioner()
+ */
+ public IDocumentPartitioner getDefaultDocumentPartitioner() {
+ return new StructuredTextPartitionerForXML();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.document.IDocumentLoader#getDocumentEncodingDetector()
+ */
+ public IDocumentCharsetDetector getDocumentEncodingDetector() {
+ return new XMLDocumentCharsetDetector();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.document.IDocumentLoader#handleLineDelimiter(java.lang.StringBuffer,
+ * org.eclipse.wst.sse.core.document.IEncodedDocument)
+ */
+ public StringBuffer handleLineDelimiter(StringBuffer originalString, IEncodedDocument theStructuredDocument) {
+ // TODO Auto-generated method stub
+ return originalString;
+ }
+
+}
+
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.java
new file mode 100644
index 0000000000..285ad87906
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.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.document;
+
+
+
+import org.eclipse.wst.sse.core.INodeAdapter;
+import org.w3c.dom.DocumentType;
+
+
+/**
+ */
+public interface DocumentTypeAdapter extends INodeAdapter {
+ static final int LOWER_CASE = 2;
+ static final int STRICT_CASE = 0;
+ static final int UPPER_CASE = 1;
+
+ /**
+ */
+ int getAttrNameCase();
+
+ /**
+ */
+ DocumentType getDocumentType();
+
+ /**
+ */
+ int getTagNameCase();
+
+ /**
+ */
+ boolean hasFeature(String feature);
+
+ /**
+ */
+ boolean isXMLType();
+
+ /**
+ */
+ void release();
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java
new file mode 100644
index 0000000000..e0a7add83d
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+/**
+ * Thrown an invalid character is specified in : XMLNode#setSource(String)
+ */
+public class InvalidCharacterException extends Exception {
+
+ private char invalidChar = 0;
+ private int offset = -1;
+
+ /**
+ */
+ public InvalidCharacterException() {
+ super();
+ }
+
+ /**
+ */
+ public InvalidCharacterException(String s) {
+ super(s);
+ }
+
+ /**
+ */
+ public InvalidCharacterException(String s, char c) {
+ super(s);
+ this.invalidChar = c;
+ }
+
+ /**
+ */
+ public InvalidCharacterException(String s, char c, int offset) {
+ super(s);
+ this.invalidChar = c;
+ this.offset = offset;
+ }
+
+ /**
+ */
+ public char getInvalidChar() {
+ return this.invalidChar;
+ }
+
+ /**
+ */
+ public int getOffset() {
+ return this.offset;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java
new file mode 100644
index 0000000000..b4398d9fa0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+/**
+ * JSPTag interface
+ */
+public interface JSPTag {
+ static final String COMMENT_CLOSE = "--%>";//$NON-NLS-1$
+ static final String COMMENT_OPEN = "<%--";//$NON-NLS-1$
+ static final String DECLARATION_TOKEN = "!";//$NON-NLS-1$
+ static final String DIRECTIVE_TOKEN = "@";//$NON-NLS-1$
+ static final String EXPRESSION_TOKEN = "=";//$NON-NLS-1$
+ static final String JSP_DECLARATION = "jsp:declaration";//$NON-NLS-1$
+ static final String JSP_DIRECTIVE = "jsp:directive";//$NON-NLS-1$
+ static final String JSP_EXPRESSION = "jsp:expression";//$NON-NLS-1$
+ static final String JSP_ROOT = "jsp:root";//$NON-NLS-1$
+
+ static final String JSP_SCRIPTLET = "jsp:scriptlet";//$NON-NLS-1$
+ static final String TAG_CLOSE = "%>";//$NON-NLS-1$
+ static final String TAG_OPEN = "<%";//$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java
new file mode 100644
index 0000000000..1c7d0c4f37
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+import org.eclipse.wst.sse.core.INodeAdapter;
+
+/**
+ */
+public interface TagAdapter extends INodeAdapter {
+
+ /**
+ */
+ String getEndTag(XMLElement element);
+
+ /**
+ */
+ String getStartTag(XMLElement element);
+
+ /**
+ */
+ boolean isEndTag();
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java
new file mode 100644
index 0000000000..60b804141b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+import org.eclipse.wst.sse.core.text.ITextRegion;
+import org.w3c.dom.Attr;
+
+
+/**
+ */
+public interface XMLAttr extends XMLNode, Attr {
+
+ /**
+ */
+ ITextRegion getEqualRegion();
+
+ /**
+ * @return
+ */
+ int getNameRegionEndOffset();
+
+ int getNameRegionStartOffset();
+
+ String getNameRegionText();
+
+ /**
+ * @return
+ */
+ int getNameRegionTextEndOffset();
+
+ int getValueRegionStartOffset();
+
+ String getValueRegionText();
+
+ /**
+ * Check if Attr has JSP in value
+ */
+ boolean hasJSPValue();
+
+ /**
+ * Check if Attr has only name but not equal sign nor value
+ */
+ boolean hasNameOnly();
+
+ /**
+ */
+ boolean isGlobalAttr();
+
+ /**
+ */
+ boolean isXMLAttr();
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java
new file mode 100644
index 0000000000..d1984d9fa0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+/**
+ * XML Namespace constants
+ */
+public interface XMLCharEntity {
+ static final String AMP_NAME = "amp";//$NON-NLS-1$
+ static final String AMP_REF = "&amp;";//$NON-NLS-1$
+ static final String AMP_VALUE = "&";//$NON-NLS-1$
+ static final String APOS_NAME = "apos";//$NON-NLS-1$
+ static final String APOS_REF = "&apos;";//$NON-NLS-1$
+ static final String APOS_VALUE = "'";//$NON-NLS-1$
+ static final String GT_NAME = "gt";//$NON-NLS-1$
+ static final String GT_REF = "&gt;";//$NON-NLS-1$
+ static final String GT_VALUE = ">";//$NON-NLS-1$
+
+ static final String LT_NAME = "lt";//$NON-NLS-1$
+ static final String LT_REF = "&lt;";//$NON-NLS-1$
+ static final String LT_VALUE = "<";//$NON-NLS-1$
+ static final String QUOT_NAME = "quot";//$NON-NLS-1$
+ static final String QUOT_REF = "&quot;";//$NON-NLS-1$
+ static final String QUOT_VALUE = "\"";//$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java
new file mode 100644
index 0000000000..a461cab1a7
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.ranges.DocumentRange;
+import org.w3c.dom.traversal.DocumentTraversal;
+
+/**
+ * This interface enables creation of DOCTYPE declaration and some DOM Level 2
+ * interfaces.
+ */
+public interface XMLDocument extends XMLNode, Document, DocumentRange, DocumentTraversal {
+
+ /**
+ * create comment element. tagName must be registered as comment element
+ * name in plugin.xml
+ *
+ * @param tagName
+ * the element name
+ * @param isJSPTag
+ * true if the element is JSP style comment (&lt;%-- ...
+ * --%&gt;)
+ * @return Element element instance
+ * @throws DOMException
+ * throwed if the element name is registered as comment
+ * element
+ */
+ Element createCommentElement(String tagName, boolean isJSPTag) throws DOMException;
+
+ /**
+ */
+ DocumentType createDoctype(String name);
+
+ /**
+ */
+ String getDocumentTypeId();
+
+ /**
+ */
+ boolean isJSPDocument();
+
+ /**
+ */
+ boolean isJSPType();
+
+ /**
+ */
+ boolean isXMLType();
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java
new file mode 100644
index 0000000000..082d4ff41a
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+import org.w3c.dom.DocumentType;
+
+/**
+ * This interface enables setting of Public and System ID for DOCTYPE
+ * declaration.
+ */
+public interface XMLDocumentType extends XMLNode, DocumentType {
+
+ /**
+ */
+ void setPublicId(String publicId);
+
+ /**
+ */
+ void setSystemId(String systemId);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.java
new file mode 100644
index 0000000000..b983975138
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.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.document;
+
+
+
+import org.w3c.dom.Element;
+
+/**
+ */
+public interface XMLElement extends XMLNode, Element {
+
+ /**
+ * @deprecated this should probably not be public, but already implemented
+ */
+ int getEndStartOffset();
+
+ /**
+ */
+ String getEndTagName();
+
+ /**
+ * @deprecated this should probably not be public, but already implemented
+ *
+ */
+ int getStartEndOffset();
+
+ /**
+ */
+ boolean hasEndTag();
+
+ /**
+ */
+ boolean hasStartTag();
+
+ /**
+ */
+ boolean isCommentTag();
+
+ /**
+ * isEmptyTag method
+ *
+ * @return boolean
+ */
+ boolean isEmptyTag();
+
+ /**
+ */
+ boolean isEndTag();
+
+ /**
+ * Returns true for "global tag" (basically, without prefix)
+ */
+ boolean isGlobalTag();
+
+ /**
+ * Returns true for no the start and the end tags
+ */
+ boolean isImplicitTag();
+
+ /**
+ * isJSPTag method
+ *
+ * @return boolean
+ */
+ boolean isJSPTag();
+
+ /**
+ */
+ boolean isStartTagClosed();
+
+ /**
+ */
+ boolean isXMLTag();
+
+ /**
+ * @deprecated this should probably not be public, but already implemented
+ */
+ void notifyEndTagChanged();
+
+ /**
+ * @deprecated this should probably not be public, but already implemented
+ */
+ void notifyStartTagChanged();
+
+ /**
+ */
+ void setCommentTag(boolean isCommentTag);
+
+ /**
+ */
+ void setEmptyTag(boolean isEmptyTag);
+
+ /**
+ */
+ void setJSPTag(boolean isJSPTag);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java
new file mode 100644
index 0000000000..5b9321bba0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+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.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+
+public interface XMLGenerator {
+
+ /**
+ */
+ String generateAttrName(Attr attr);
+
+ /**
+ */
+ String generateAttrValue(Attr attr);
+
+ /**
+ */
+ String generateAttrValue(Attr attr, char quote);
+
+ /**
+ */
+ String generateAttrValue(String value, char quote);
+
+ /**
+ * generateCDATASection method
+ *
+ * @return java.lang.String
+ * @param comment
+ * org.w3c.dom.CDATASection
+ */
+ String generateCDATASection(CDATASection cdata);
+
+ /**
+ * generateChild method
+ *
+ * @return java.lang.String
+ * @param org.w3c.dom.Node
+ */
+ String generateChild(Node parentNode);
+
+ /**
+ */
+ String generateCloseTag(Node node);
+
+ /**
+ * generateComment method
+ *
+ * @return java.lang.String
+ * @param comment
+ * org.w3c.dom.Comment
+ */
+ String generateComment(Comment comment);
+
+ /**
+ * generateDoctype method
+ *
+ * @return java.lang.String
+ * @param docType
+ * org.w3c.dom.DocumentType
+ */
+ String generateDoctype(DocumentType docType);
+
+ /**
+ * generateElement method
+ *
+ * @return java.lang.String
+ * @param element
+ * Element
+ */
+ String generateElement(Element element);
+
+ /**
+ * generateEndTag method
+ *
+ * @return java.lang.String
+ * @param element
+ * org.w3c.dom.Element
+ */
+ String generateEndTag(Element element);
+
+ /**
+ * generateEntityRef method
+ *
+ * @return java.lang.String
+ * @param entityRef
+ * org.w3c.dom.EntityReference
+ */
+ String generateEntityRef(EntityReference entityRef);
+
+ /**
+ * generatePI method
+ *
+ * @return java.lang.String
+ * @param pi
+ * org.w3c.dom.ProcessingInstruction
+ */
+ String generatePI(ProcessingInstruction pi);
+
+ /**
+ * generateSource method
+ *
+ * @return java.lang.String
+ * @param node
+ * org.w3c.dom.Node
+ */
+ String generateSource(Node node);
+
+ /**
+ * generateStartTag method
+ *
+ * @return java.lang.String
+ * @param element
+ * Element
+ */
+ String generateStartTag(Element element);
+
+ /**
+ */
+ String generateTagName(Element element);
+
+ /**
+ * generateText method
+ *
+ * @return java.lang.String
+ * @param text
+ * org.w3c.dom.Text
+ */
+ String generateText(Text text);
+
+ /**
+ */
+ String generateTextData(Text text, String data);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.java
new file mode 100644
index 0000000000..f95cff4d25
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.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.document;
+
+import org.eclipse.wst.sse.core.IStructuredModel;
+
+
+
+/**
+ */
+public interface XMLModel extends IStructuredModel {
+
+ XMLDocument getDocument();
+
+ /**
+ */
+ XMLGenerator getGenerator();
+
+ /**
+ */
+ XMLModelNotifier getModelNotifier();
+
+ /**
+ */
+ void setModelNotifier(XMLModelNotifier notifier);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java
new file mode 100644
index 0000000000..1cee885546
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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.document;
+
+
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public interface XMLModelNotifier {
+
+ /**
+ * attrReplaced method
+ *
+ * @param element
+ * org.w3c.dom.Element
+ * @param newAttr
+ * org.w3c.dom.Attr
+ * @param oldAttr
+ * org.w3c.dom.Attr
+ */
+ void attrReplaced(Element element, Attr newAttr, Attr oldAttr);
+
+ /**
+ */
+ void beginChanging();
+
+ /**
+ */
+ void beginChanging(boolean newModel);
+
+ /**
+ * Cancel pending notifications. This is called in the context of
+ * "reinitialization" so is assumed ALL notifications can be safely
+ * canceled, assuming that once factories and adapters are re-initialized
+ * they will be re-notified as text is set in model, if still appropriate.
+ */
+ void cancelPending();
+
+ /**
+ * childReplaced method
+ *
+ * @param parentNode
+ * org.w3c.dom.Node
+ * @param newChild
+ * org.w3c.dom.Node
+ * @param oldChild
+ * org.w3c.dom.Node
+ */
+ void childReplaced(Node parentNode, Node newChild, Node oldChild);
+
+ /**
+ */
+ void editableChanged(Node node);
+
+ /**
+ */
+ void endChanging();
+
+ /**
+ */
+ void endTagChanged(Element element);
+
+ /**
+ */
+ boolean hasChanged();
+
+ /**
+ */
+ boolean isChanging();
+
+ /**
+ */
+ void propertyChanged(Node node);
+
+ /**
+ */
+ void startTagChanged(Element element);
+
+ /**
+ */
+ void structureChanged(Node node);
+
+ /**
+ * valueChanged method
+ *
+ * @param node
+ * org.w3c.dom.Node
+ */
+ void valueChanged(Node node);
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.java
new file mode 100644
index 0000000000..04188a6781
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.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.document;
+
+
+
+/**
+ * XML Namespace constants
+ */
+public interface XMLNamespace {
+
+ static final String XMLNS = "xmlns";//$NON-NLS-1$
+ static final String XMLNS_PREFIX = "xmlns:";//$NON-NLS-1$
+ static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";//$NON-NLS-1$
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java
new file mode 100644
index 0000000000..b20058190c
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * 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.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;
+
+/**
+ * A interface to make concept clearer, just to denote the combination of
+ * three other interfaces.
+ *
+ */
+public interface XMLNode extends org.eclipse.wst.sse.core.IndexedRegion, org.eclipse.wst.sse.core.INodeNotifier, org.w3c.dom.Node {
+
+ /**
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ IStructuredDocumentRegion getEndStructuredDocumentRegion();
+
+ /**
+ */
+ IStructuredDocumentRegion getFirstStructuredDocumentRegion();
+
+ /**
+ */
+ IStructuredDocumentRegion getLastStructuredDocumentRegion();
+
+ /**
+ */
+ XMLModel getModel();
+
+ /**
+ */
+ ITextRegion getNameRegion();
+
+ /**
+ */
+ String getSource();
+
+ /**
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion
+ */
+ IStructuredDocumentRegion getStartStructuredDocumentRegion();
+
+ /**
+ *
+ * @return com.ibm.sed.structuredDocument.IStructuredDocument
+ */
+ IStructuredDocument getStructuredDocument();
+
+ /**
+ */
+ ITextRegion getValueRegion();
+
+ /**
+ */
+ String getValueSource();
+
+ /**
+ *
+ * @return boolean Whether children of the element can be appended or
+ * removed.
+ */
+ boolean isChildEditable();
+
+ /**
+ */
+ boolean isClosed();
+
+ /**
+ * isContainer method
+ *
+ * @return boolean
+ */
+ boolean isContainer();
+
+ /**
+ */
+ boolean isDataEditable();
+
+ /**
+ */
+ void setChildEditable(boolean editable);
+
+ /**
+ */
+ void setDataEditable(boolean editable);
+
+ /**
+ * faster approach to set
+ */
+ void setEditable(boolean editable, boolean deep);
+
+ /**
+ * Sets the specified raw source to the Text node. Throws
+ * InvalidCharacterException when the specified raw source includes
+ * invalid characters, such as, ' <', '>' and '&'. Valid character
+ * entities, such as, "&amp;lt;", are accepted.
+ */
+ void setSource(String source) throws InvalidCharacterException;
+
+ /**
+ * Sets the specified raw source to the Text or Attr node's value. When
+ * the specified raw source includes invalid characters, such as, ' <',
+ * '>' and '&', converts them. Valid character entities, such as,
+ * "&amp;lt;", are accepted.
+ */
+ void setValueSource(String source);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.java
new file mode 100644
index 0000000000..fe80a06a73
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.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.document;
+
+
+
+import org.w3c.dom.Text;
+
+/**
+ */
+public interface XMLText extends XMLNode, Text {
+
+ /**
+ * Appends the content of the text node
+ */
+ void appendText(Text text);
+
+ /**
+ * Inserts the content of the text node at the specified position
+ */
+ void insertText(Text text, int offset);
+
+ /**
+ */
+ boolean isInvalid();
+
+ /**
+ */
+ boolean isWhitespace();
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java
new file mode 100644
index 0000000000..bdde4b27a0
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.encoding;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.wst.sse.core.document.DocumentReader;
+import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector;
+import org.eclipse.wst.xml.core.contenttype.XMLResourceEncodingDetector;
+
+
+/**
+ * This class reads and parses first of XML file to get encoding.
+ *
+ */
+public class XMLDocumentCharsetDetector extends XMLResourceEncodingDetector implements IDocumentCharsetDetector {
+
+ /**
+ * XMLLoader constructor comment.
+ */
+ public XMLDocumentCharsetDetector() {
+ super();
+ }
+
+ public void set(IDocument document) {
+ set(new DocumentReader(document, 0));
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java
new file mode 100644
index 0000000000..a87b340a1b
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * 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.encoding;
+
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.wst.common.encoding.ContentTypeEncodingPreferences;
+import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier;
+import org.eclipse.wst.sse.core.document.AbstractDocumentLoader;
+import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector;
+import org.eclipse.wst.sse.core.document.IDocumentLoader;
+import org.eclipse.wst.sse.core.document.IEncodedDocument;
+import org.eclipse.wst.sse.core.document.StructuredDocumentFactory;
+import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocument;
+import org.eclipse.wst.sse.core.parser.RegionParser;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser;
+import org.eclipse.wst.xml.core.internal.parser.XMLStructuredDocumentReParser;
+import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML;
+
+
+/**
+ * This class reads an XML file and creates an XML Structured Model.
+ *
+ */
+public class XMLDocumentLoader extends AbstractDocumentLoader {
+
+ public XMLDocumentLoader() {
+ super();
+ }
+
+ public IDocumentPartitioner getDefaultDocumentPartitioner() {
+ return new StructuredTextPartitionerForXML();
+ }
+
+ public IDocumentCharsetDetector getDocumentEncodingDetector() {
+ if (fDocumentEncodingDetector == null) {
+ fDocumentEncodingDetector = new XMLDocumentCharsetDetector();
+ }
+ return fDocumentEncodingDetector;
+ }
+
+ public RegionParser getParser() {
+ return new XMLSourceParser();
+ }
+
+ protected String getPreferredNewLineDelimiter() {
+ return ContentTypeEncodingPreferences.getPreferredNewLineDelimiter(IContentTypeIdentifier.ContentTypeID_SSEXML);
+ }
+
+ protected String getSpecDefaultEncoding() {
+ // by default, UTF-8 as per XML spec
+ final String enc = "UTF-8"; //$NON-NLS-1$
+ return enc;
+ }
+
+ protected IEncodedDocument newEncodedDocument() {
+ IStructuredDocument structuredDocument = StructuredDocumentFactory.getNewStructuredDocumentInstance(getParser());
+ if (structuredDocument instanceof BasicStructuredDocument) {
+ ((BasicStructuredDocument) structuredDocument).setReParser(new XMLStructuredDocumentReParser());
+ }
+ return structuredDocument;
+ }
+
+ public IDocumentLoader newInstance() {
+ return new XMLDocumentLoader();
+ }
+
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.java
new file mode 100644
index 0000000000..f962f15db6
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.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.format;
+
+import org.eclipse.wst.sse.core.format.IStructuredFormatContraints;
+import org.eclipse.wst.sse.core.util.StringUtils;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Node;
+
+
+public class CommentNodeFormatter extends NodeFormatter {
+
+ protected String adjustIndentations(String aString, String lineIndent, String singleIndent) {
+ String result = new String();
+
+ int indexOfLineDelimiter = StringUtils.indexOfLineDelimiter(aString);
+ result = aString.substring(0, indexOfLineDelimiter);
+ while (indexOfLineDelimiter != -1) {
+ // Before find the next LineDelimiter, we have to figure out the
+ // size of the current LineDelimiter
+ // so we can figure out how many bytes to skip before finding the
+ // next LineDelimiter.
+ // Otherwise, we may treat the LF in CRLF as the next
+ // LineDelimiter.
+ int lineDelimiterSize = 1;
+ if (aString.length() >= indexOfLineDelimiter + 2 && aString.substring(indexOfLineDelimiter, indexOfLineDelimiter + 1).compareTo(CR) == 0 && aString.substring(indexOfLineDelimiter + 1, indexOfLineDelimiter + 2).compareTo(LF) == 0)
+ lineDelimiterSize = 2;
+
+ int indexOfNextLineDelimiter = StringUtils.indexOfLineDelimiter(aString, indexOfLineDelimiter + lineDelimiterSize);
+ int indexOfNonblank = StringUtils.indexOfNonblank(aString, indexOfLineDelimiter);
+
+ if (indexOfNonblank != -1) {
+ if (indexOfNextLineDelimiter == -1) {
+ // last line; copy till the end
+ result += lineIndent + singleIndent + aString.substring(indexOfNonblank);
+ } else if (indexOfNextLineDelimiter != -1 && indexOfNextLineDelimiter < indexOfNonblank) {
+ // blank line; just add a indent
+ result += lineIndent + singleIndent;
+ } else {
+ // copy all text between indexOfNonblank and
+ // indexOfNextLineDelimiter
+ result += lineIndent + singleIndent + aString.substring(indexOfNonblank, indexOfNextLineDelimiter);
+ }
+
+ indexOfLineDelimiter = indexOfNextLineDelimiter;
+ } else {
+ if (indexOfNextLineDelimiter == -1) {
+ result += lineIndent;
+ } else {
+ // blank line; just add a indent
+ result += lineIndent + singleIndent;
+ }
+
+ indexOfLineDelimiter = indexOfNextLineDelimiter;
+ }
+ }
+
+ return result;
+ }
+
+ protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null) {
+ // lineDelimiterFound means multi line comment
+ String nodeValue = node.getNodeValue();
+ boolean lineDelimiterFoundInComment = StringUtils.containsLineDelimiter(nodeValue);
+
+ if (lineDelimiterFoundInComment) {
+ // format indentation before node
+ formatIndentationBeforeNode(node, formatContraints);
+
+ // adjust indentations in multi line comment
+ String lineDelimiter = node.getModel().getStructuredDocument().getLineDelimiter();
+ String lineIndent = formatContraints.getCurrentIndent();
+ String singleIndent = getFormatPreferences().getIndent();
+ String newNodevalue = adjustIndentations(nodeValue, lineDelimiter + lineIndent, singleIndent);
+ if (nodeValue.compareTo(newNodevalue) != 0)
+ node.setNodeValue(newNodevalue);
+ }
+
+ if (!nodeHasSiblings(node) || (node.getPreviousSibling() != null && node.getPreviousSibling().getNodeType() == Node.TEXT_NODE && !StringUtils.containsLineDelimiter(node.getPreviousSibling().getNodeValue()) && node.getNextSibling() == null)) {
+ // single child
+ // or inline comment after text
+ // do nothing
+ } else
+ // format indentation after node
+ formatIndentationAfterNode(node, formatContraints);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java
new file mode 100644
index 0000000000..ee671a9925
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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.format;
+
+import org.eclipse.wst.sse.core.format.IStructuredFormatContraints;
+import org.eclipse.wst.sse.core.format.IStructuredFormatter;
+import org.eclipse.wst.xml.core.document.XMLNode;
+
+
+public class DocumentNodeFormatter extends NodeFormatter {
+ protected void formatChildren(XMLNode node, IStructuredFormatContraints formatContraints) {
+ String singleIndent = getFormatPreferences().getIndent();
+ String lineIndent = formatContraints.getCurrentIndent();
+
+ if (node != null && (fProgressMonitor == null || !fProgressMonitor.isCanceled())) {
+ // normalize node first to combine adjacent text nodes
+ node.normalize();
+
+ XMLNode nextChild = (XMLNode) node.getFirstChild();
+ while (nextChild != null) {
+ XMLNode eachChildNode = nextChild;
+ nextChild = (XMLNode) eachChildNode.getNextSibling();
+ IStructuredFormatter formatter = getFormatter(eachChildNode);
+ IStructuredFormatContraints childFormatContraints = formatter.getFormatContraints();
+ String childIndent = lineIndent + singleIndent;
+ childFormatContraints.setCurrentIndent(childIndent);
+ childFormatContraints.setClearAllBlankLines(formatContraints.getClearAllBlankLines());
+
+ // format each child
+ formatter.format(eachChildNode, childFormatContraints);
+
+ if (nextChild != null && nextChild.getParentNode() == null)
+ // nextNode is deleted during format
+ nextChild = (XMLNode) eachChildNode.getNextSibling();
+ }
+ }
+ }
+
+ protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null)
+ formatChildren(node, formatContraints);
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java
new file mode 100644
index 0000000000..52d63d9a81
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java
@@ -0,0 +1,357 @@
+/*******************************************************************************
+ * 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.format;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration;
+import org.eclipse.wst.common.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+import org.eclipse.wst.sse.core.format.IStructuredFormatContraints;
+import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapter;
+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.sse.core.util.StringUtils;
+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.XMLNode;
+import org.eclipse.wst.xml.core.internal.document.AttrImpl;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+
+public class ElementNodeFormatter extends DocumentNodeFormatter {
+ static protected final char DOUBLE_QUOTE = '"';//$NON-NLS-1$
+ static protected final String DOUBLE_QUOTES = "\"\"";//$NON-NLS-1$
+ static protected final char EQUAL_CHAR = '='; // equal sign$NON-NLS-1$
+ static protected final String PRESERVE = "preserve";//$NON-NLS-1$
+ static protected final String PRESERVE_QUOTED = "\"preserve\"";//$NON-NLS-1$
+ static protected final char SINGLE_QUOTE = '\'';//$NON-NLS-1$
+ static protected final String XML_SPACE = "xml:space";//$NON-NLS-1$
+
+ protected void formatEndTag(XMLNode node, IStructuredFormatContraints formatContraints) {
+ String tagName = node.getNodeName();
+
+ if (!isEndTagMissing(node)) {
+ // end tag exists
+
+ IStructuredDocument structuredDocument = node.getModel().getStructuredDocument();
+ String lineDelimiter = structuredDocument.getLineDelimiter();
+ String nodeIndentation = getNodeIndent(node);
+ XMLNode lastChild = (XMLNode) node.getLastChild();
+ if (lastChild != null && lastChild.getNodeType() != Node.TEXT_NODE) {
+ if (isEndTagMissing(lastChild)) {
+ // find deepest child
+ XMLNode deepestChild = (XMLNode) lastChild.getLastChild();
+ while (deepestChild != null && deepestChild.getLastChild() != null && isEndTagMissing(deepestChild)) {
+ lastChild = deepestChild;
+ deepestChild = (XMLNode) deepestChild.getLastChild();
+ }
+
+ if (deepestChild != null) {
+ if (deepestChild.getNodeType() == Node.TEXT_NODE) {
+ // Special indentation handling if lastChild's end
+ // tag is missing and deepestChild is a text node.
+ String nodeText = deepestChild.getNodeValue();
+
+ if (!nodeText.endsWith(lineDelimiter + nodeIndentation)) {
+ nodeText = StringUtils.appendIfNotEndWith(nodeText, lineDelimiter);
+ nodeText = StringUtils.appendIfNotEndWith(nodeText, nodeIndentation);
+ }
+
+ replaceNodeValue(deepestChild, nodeText);
+ } else
+ insertAfterNode(lastChild, lineDelimiter + nodeIndentation);
+ }
+ } else
+ // indent end tag
+ insertAfterNode(lastChild, lineDelimiter + nodeIndentation);
+ } else if (lastChild == null && firstStructuredDocumentRegionContainsLineDelimiters(node)) {
+ // indent end tag
+ replace(structuredDocument, node.getFirstStructuredDocumentRegion().getEndOffset(), 0, lineDelimiter + nodeIndentation);
+ }
+
+ // format end tag name
+ IStructuredDocumentRegion endTagStructuredDocumentRegion = node.getLastStructuredDocumentRegion();
+ if (endTagStructuredDocumentRegion.getRegions().size() >= 3) {
+ ITextRegion endTagNameRegion = endTagStructuredDocumentRegion.getRegions().get(1);
+ removeRegionSpaces(node, endTagStructuredDocumentRegion, endTagNameRegion);
+ }
+ }
+ }
+
+ protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null) {
+ // format indentation before node
+ formatIndentationBeforeNode(node, formatContraints);
+
+ // format start tag
+ XMLNode newNode = node;
+ int startTagStartOffset = node.getStartOffset();
+ XMLModel structuredModel = node.getModel();
+
+ formatStartTag(node, formatContraints);
+ // save new node
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset);
+
+ IStructuredDocumentRegion flatNode = newNode.getFirstStructuredDocumentRegion();
+ if (flatNode != null) {
+ ITextRegionList regions = flatNode.getRegions();
+ ITextRegion lastRegion = regions.get(regions.size() - 1);
+ // format children and end tag if not empty start tag
+ if (lastRegion.getType() != XMLRegionContext.XML_EMPTY_TAG_CLOSE) {
+ // format children
+ formatChildren(newNode, formatContraints);
+
+ // save new node
+ newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset);
+
+ // format end tag
+ formatEndTag(newNode, formatContraints);
+ }
+ }
+
+ // format indentation after node
+ formatIndentationAfterNode(newNode, formatContraints);
+ }
+ }
+
+ /**
+ * This method formats the start tag name, and formats the attributes if
+ * available.
+ */
+ protected void formatStartTag(XMLNode node, IStructuredFormatContraints formatContraints) {
+ String singleIndent = getFormatPreferences().getIndent();
+ String lineIndent = formatContraints.getCurrentIndent();
+ String attrIndent = lineIndent + singleIndent;
+ boolean splitMultiAttrs = ((IStructuredFormatPreferencesXML) fFormatPreferences).getSplitMultiAttrs();
+ IStructuredDocumentRegion flatNode = node.getFirstStructuredDocumentRegion();
+ NamedNodeMap attributes = node.getAttributes();
+ String tagName = node.getNodeName();
+
+ // Note: attributes should not be null even if the node has no
+ // attributes. However, attributes.getLength() will be 0. But, check
+ // for null just in case.
+ if (attributes != null) {
+ // compute current available line width
+ int currentAvailableLineWidth = 0;
+ try {
+ // 1 is for "<"
+ int nodeNameOffset = node.getStartOffset() + 1 + node.getNodeName().length();
+ int lineOffset = node.getStructuredDocument().getLineInformationOfOffset(nodeNameOffset).getOffset();
+ String text = node.getStructuredDocument().get(lineOffset, nodeNameOffset - lineOffset);
+ int usedWidth = getIndentationLength(text);
+ currentAvailableLineWidth = getFormatPreferences().getLineWidth() - usedWidth;
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+
+ StringBuffer stringBuffer = new StringBuffer();
+ String lineDelimiter = node.getModel().getStructuredDocument().getLineDelimiter();
+ int attrLength = attributes.getLength();
+ int lastUndefinedRegionOffset = 0;
+ for (int i = 0; i < attrLength; i++) {
+ AttrImpl attr = (AttrImpl) attributes.item(i);
+ ITextRegion nameRegion = attr.getNameRegion();
+ ITextRegion equalRegion = attr.getEqualRegion();
+ ITextRegion valueRegion = attr.getValueRegion();
+
+ // append undefined regions
+ String undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, attr.getStartOffset() - lastUndefinedRegionOffset);
+ stringBuffer.append(undefinedRegion);
+ lastUndefinedRegionOffset = attr.getStartOffset();
+
+ // check for xml:space attribute
+ if (flatNode.getText(nameRegion).compareTo(XML_SPACE) == 0) {
+ if (valueRegion == null) {
+ ModelQueryAdapter adapter = (ModelQueryAdapter) ((XMLDocument) node.getOwnerDocument()).getAdapterFor(ModelQueryAdapter.class);
+ CMElementDeclaration elementDeclaration = (CMElementDeclaration) adapter.getModelQuery().getCMNode(node);
+ if (elementDeclaration == null)
+ // CMElementDeclaration not found, default to
+ // PRESERVE
+ formatContraints.setClearAllBlankLines(false);
+ else {
+ CMAttributeDeclaration attributeDeclaration = (CMAttributeDeclaration) elementDeclaration.getAttributes().getNamedItem(XML_SPACE);
+ if (attributeDeclaration == null)
+ // CMAttributeDeclaration not found, default
+ // to PRESERVE
+ formatContraints.setClearAllBlankLines(false);
+ else {
+ String defaultValue = attributeDeclaration.getAttrType().getImpliedValue();
+
+ if (defaultValue.compareTo(PRESERVE) == 0)
+ formatContraints.setClearAllBlankLines(false);
+ else
+ formatContraints.setClearAllBlankLines(getFormatPreferences().getClearAllBlankLines());
+ }
+ }
+ } else {
+ XMLGenerator generator = node.getModel().getGenerator();
+ String newAttrValue = generator.generateAttrValue(attr);
+
+ // There is a problem in
+ // StructuredDocumentRegionUtil.getAttrValue(ITextRegion)
+ // when the region is instanceof ContextRegion.
+ // Workaround for now.
+ if (flatNode.getText(valueRegion).length() == 1) {
+ char firstChar = flatNode.getText(valueRegion).charAt(0);
+ if ((firstChar == DOUBLE_QUOTE) || (firstChar == SINGLE_QUOTE))
+ newAttrValue = DOUBLE_QUOTES;
+ }
+
+ if (newAttrValue.compareTo(PRESERVE_QUOTED) == 0)
+ formatContraints.setClearAllBlankLines(false);
+ else
+ formatContraints.setClearAllBlankLines(getFormatPreferences().getClearAllBlankLines());
+ }
+ }
+
+ if (splitMultiAttrs && attrLength > 1) {
+ stringBuffer.append(lineDelimiter + attrIndent);
+ stringBuffer.append(flatNode.getText(nameRegion));
+ if (valueRegion != null) {
+ // append undefined regions
+ undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(equalRegion) - lastUndefinedRegionOffset);
+ stringBuffer.append(undefinedRegion);
+ lastUndefinedRegionOffset = flatNode.getStartOffset(equalRegion);
+
+ stringBuffer.append(EQUAL_CHAR);
+
+ // append undefined regions
+ undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(valueRegion) - lastUndefinedRegionOffset);
+ stringBuffer.append(undefinedRegion);
+ lastUndefinedRegionOffset = flatNode.getStartOffset(valueRegion);
+
+ // Note: trim() should not be needed for
+ // valueRegion.getText(). Just a workaround for a
+ // problem found in valueRegion for now.
+ stringBuffer.append(flatNode.getText(valueRegion).trim());
+ }
+ } else {
+ if (valueRegion != null) {
+ int textLength = 1 + flatNode.getText(nameRegion).length() + 1 + flatNode.getText(valueRegion).length();
+ if (i == attrLength - 1) {
+ if (flatNode != null) {
+ ITextRegionList regions = flatNode.getRegions();
+ ITextRegion lastRegion = regions.get(regions.size() - 1);
+ if (lastRegion.getType() != XMLRegionContext.XML_EMPTY_TAG_CLOSE)
+ // 3 is for " />"
+ textLength += 3;
+ else
+ // 1 is for ">"
+ textLength++;
+ }
+ }
+
+ if (currentAvailableLineWidth >= textLength) {
+ stringBuffer.append(SPACE_CHAR);
+ currentAvailableLineWidth--;
+ } else {
+ stringBuffer.append(lineDelimiter + attrIndent);
+ currentAvailableLineWidth = getFormatPreferences().getLineWidth() - attrIndent.length();
+ }
+
+ stringBuffer.append(flatNode.getText(nameRegion));
+
+ // append undefined regions
+ undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(equalRegion) - lastUndefinedRegionOffset);
+ stringBuffer.append(undefinedRegion);
+ lastUndefinedRegionOffset = flatNode.getStartOffset(equalRegion);
+
+ stringBuffer.append(EQUAL_CHAR);
+
+ // append undefined regions
+ undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(valueRegion) - lastUndefinedRegionOffset);
+ stringBuffer.append(undefinedRegion);
+ lastUndefinedRegionOffset = flatNode.getStartOffset(valueRegion);
+
+ // Note: trim() should not be needed for
+ // valueRegion.getText(). Just a workaround for a
+ // problem found in valueRegion for now.
+ stringBuffer.append(flatNode.getText(valueRegion).trim());
+
+ currentAvailableLineWidth -= flatNode.getText(nameRegion).length();
+ currentAvailableLineWidth--;
+ currentAvailableLineWidth -= flatNode.getText(valueRegion).trim().length();
+ } else {
+ if (currentAvailableLineWidth >= 1 + flatNode.getText(nameRegion).length()) {
+ stringBuffer.append(SPACE_CHAR);
+ currentAvailableLineWidth--;
+ } else {
+ stringBuffer.append(lineDelimiter + attrIndent);
+ currentAvailableLineWidth = getFormatPreferences().getLineWidth() - attrIndent.length();
+ }
+
+ stringBuffer.append(flatNode.getText(nameRegion));
+
+ currentAvailableLineWidth -= flatNode.getText(nameRegion).length();
+ }
+ }
+ }
+
+ // append undefined regions
+ String undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, node.getEndOffset() - lastUndefinedRegionOffset);
+ stringBuffer.append(undefinedRegion);
+
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ // 1 is for "<"
+ int offset = node.getStartOffset() + 1 + node.getNodeName().length();
+ // 1 is for "<"
+ int length = node.getFirstStructuredDocumentRegion().getTextLength() - 1 - node.getNodeName().length();
+
+ if (flatNode != null) {
+ ITextRegionList regions = flatNode.getRegions();
+ ITextRegion firstRegion = regions.get(0);
+ ITextRegion lastRegion = regions.get(regions.size() - 1);
+
+ if (firstRegion.getType() == XMLRegionContext.XML_END_TAG_OPEN)
+ // skip formatting for end tags in this format: </tagName>
+ return;
+ else {
+ if (lastRegion.getType() == XMLRegionContext.XML_TAG_CLOSE || lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE)
+ length = length - lastRegion.getLength();
+
+ if (lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE)
+ // leave space before XML_EMPTY_TAG_CLOSE: <tagName />
+ stringBuffer.append(SPACE_CHAR);
+ }
+ }
+
+ replace(structuredDocument, offset, length, stringBuffer.toString());
+ }
+ }
+
+ protected String getUndefinedRegions(XMLNode node, int startOffset, int length) {
+ String result = new String();
+
+ IStructuredDocumentRegion flatNode = node.getFirstStructuredDocumentRegion();
+ ITextRegionList regions = flatNode.getRegions();
+ for (int i = 0; i < regions.size(); i++) {
+ ITextRegion region = regions.get(i);
+ String regionType = region.getType();
+ int regionStartOffset = flatNode.getStartOffset(region);
+
+ if (regionType.compareTo(XMLRegionContext.UNDEFINED) == 0 && regionStartOffset >= startOffset && regionStartOffset < startOffset + length)
+ result = result + flatNode.getFullText(region);
+ }
+
+ if (result.length() > 0)
+ return SPACE + result.trim();
+ else
+ return result;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java
new file mode 100644
index 0000000000..d9f2b0df10
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.format;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.wst.sse.core.IModelManagerPlugin;
+import org.eclipse.wst.sse.core.format.AbstractStructuredFormatProcessor;
+import org.eclipse.wst.sse.core.format.IStructuredFormatPreferences;
+import org.eclipse.wst.sse.core.format.IStructuredFormatter;
+import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames;
+import org.eclipse.wst.xml.core.XMLModelPlugin;
+import org.eclipse.wst.xml.core.internal.document.CDATASectionImpl;
+import org.w3c.dom.Node;
+
+
+public class FormatProcessorXML extends AbstractStructuredFormatProcessor {
+ protected IStructuredFormatPreferences fFormatPreferences = null;
+
+ protected String getFileExtension() {
+ return "xml"; //$NON-NLS-1$
+ }
+
+ public IStructuredFormatPreferences getFormatPreferences() {
+ if (fFormatPreferences == null) {
+ fFormatPreferences = new StructuredFormatPreferencesXML();
+
+ Preferences preferences = getModelPreferences();
+ if (preferences != null) {
+ fFormatPreferences.setLineWidth(preferences.getInt(CommonModelPreferenceNames.LINE_WIDTH));
+ ((IStructuredFormatPreferencesXML) fFormatPreferences).setSplitMultiAttrs(preferences.getBoolean(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS));
+ fFormatPreferences.setClearAllBlankLines(preferences.getBoolean(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES));
+
+ if (preferences.getBoolean(CommonModelPreferenceNames.INDENT_USING_TABS))
+ fFormatPreferences.setIndent("\t"); //$NON-NLS-1$
+ else {
+ int tabWidth = getModelManagerPlugin().getPluginPreferences().getInt(CommonModelPreferenceNames.TAB_WIDTH);
+ String indent = ""; //$NON-NLS-1$
+ for (int i = 0; i < tabWidth; i++) {
+ indent += " "; //$NON-NLS-1$
+ }
+ fFormatPreferences.setIndent(indent);
+ }
+ }
+ }
+
+ return fFormatPreferences;
+ }
+
+ protected IStructuredFormatter getFormatter(Node node) {
+ // 262135 - NPE during format of empty document
+ if (node == null)
+ return null;
+
+ short nodeType = node.getNodeType();
+ IStructuredFormatter formatter = null;
+ switch (nodeType) {
+ case Node.ELEMENT_NODE : {
+ formatter = new ElementNodeFormatter();
+ break;
+ }
+ case Node.TEXT_NODE : {
+ if (node instanceof CDATASectionImpl)
+ formatter = new NodeFormatter();
+ else
+ formatter = new TextNodeFormatter();
+ break;
+ }
+ case Node.COMMENT_NODE : {
+ formatter = new CommentNodeFormatter();
+ break;
+ }
+ case Node.PROCESSING_INSTRUCTION_NODE : {
+ formatter = new NodeFormatter();
+ break;
+ }
+ case Node.DOCUMENT_NODE : {
+ formatter = new DocumentNodeFormatter();
+ break;
+ }
+ default : {
+ formatter = new NodeFormatter();
+ }
+ }
+
+ // init fomatter
+ formatter.setFormatPreferences(getFormatPreferences());
+ formatter.setProgressMonitor(fProgressMonitor);
+
+ return formatter;
+ }
+
+ private IModelManagerPlugin getModelManagerPlugin() {
+
+ IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID);
+ return plugin;
+ }
+
+ protected Preferences getModelPreferences() {
+ return XMLModelPlugin.getDefault().getPluginPreferences();
+ }
+
+ protected void refreshFormatPreferences() {
+ fFormatPreferences = null;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.java
new file mode 100644
index 0000000000..bc3faccf25
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.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.format;
+
+import org.eclipse.wst.sse.core.format.IStructuredFormatPreferences;
+
+public interface IStructuredFormatPreferencesXML extends IStructuredFormatPreferences {
+ boolean getSplitMultiAttrs();
+
+ void setSplitMultiAttrs(boolean splitMultiAttrs);
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java
new file mode 100644
index 0000000000..1948cdfc87
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java
@@ -0,0 +1,775 @@
+/*******************************************************************************
+ * 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.format;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.wst.sse.core.IModelManagerPlugin;
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+import org.eclipse.wst.sse.core.format.IStructuredFormatContraints;
+import org.eclipse.wst.sse.core.format.IStructuredFormatPreferences;
+import org.eclipse.wst.sse.core.format.IStructuredFormatter;
+import org.eclipse.wst.sse.core.format.StructuredFormatContraints;
+import org.eclipse.wst.sse.core.internal.parser.ContextRegion;
+import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames;
+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.sse.core.util.StringUtils;
+import org.eclipse.wst.xml.core.XMLModelPlugin;
+import org.eclipse.wst.xml.core.document.XMLModel;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.eclipse.wst.xml.core.internal.document.CDATASectionImpl;
+import org.eclipse.wst.xml.core.internal.parser.regions.TagNameRegion;
+import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts;
+import org.eclipse.wst.xml.core.parser.XMLRegionContext;
+import org.w3c.dom.Node;
+
+
+public class NodeFormatter implements IStructuredFormatter {
+ static protected final String CR = "\r"; //$NON-NLS-1$
+ static protected final String CRLF = "\r\n"; //$NON-NLS-1$
+ static protected final String DELIMITERS = " \t\n\r\f"; //$NON-NLS-1$
+ static protected final String EMPTY_STRING = ""; //$NON-NLS-1$
+ static protected final String FF = "\f"; //$NON-NLS-1$
+ static protected final String LF = "\n"; //$NON-NLS-1$
+ static protected final String SPACE = " "; //$NON-NLS-1$
+ static protected final char SPACE_CHAR = ' '; //$NON-NLS-1$
+ static protected final String TAB = "\t"; //$NON-NLS-1$
+ static protected final char TAB_CHAR = '\t'; //$NON-NLS-1$
+ protected IStructuredFormatContraints fFormatContraints = null;
+ protected IStructuredFormatPreferences fFormatPreferences = null;
+ protected IProgressMonitor fProgressMonitor = null;
+
+ protected String compressSpaces(String string, IStructuredFormatContraints formatContraints) {
+ /*
+ * Note that the StructuredTextEditor supports mixed new line
+ * characters (CR, LF, CRLF) in one file. We have to handle that when
+ * we try to preserve blank lines.
+ */
+ String[] stringArray = null;
+ boolean clearAllBlankLines = formatContraints.getClearAllBlankLines();
+
+ if (clearAllBlankLines)
+ stringArray = StringUtils.asArray(string);
+ else
+ stringArray = StringUtils.asArray(string, DELIMITERS, true);
+
+ StringBuffer compressedString = new StringBuffer();
+ if (stringArray.length > 0) {
+ boolean cr = false, lf = false, cr2 = false, nonSpace = true;
+
+ if (stringArray[0].compareTo(CR) == 0)
+ cr = true;
+ else if (stringArray[0].compareTo(LF) == 0)
+ lf = true;
+ else if ((stringArray[0].compareTo(SPACE) != 0) && (stringArray[0].compareTo(TAB) != 0) && (stringArray[0].compareTo(FF) != 0)) {
+ compressedString.append(stringArray[0]);
+ nonSpace = true;
+ }
+
+ for (int i = 1; i < stringArray.length; i++) {
+ if (stringArray[i].compareTo(CR) == 0) {
+ if (cr && lf) {
+ if (nonSpace) {
+ compressedString.append(CR + LF);
+ nonSpace = false;
+ }
+ compressedString.append(stringArray[i]);
+ cr2 = true;
+ } else if (cr) {
+ if (nonSpace) {
+ compressedString.append(CR);
+ nonSpace = false;
+ }
+ compressedString.append(stringArray[i]);
+ cr2 = true;
+ } else
+ cr = true;
+ } else if (stringArray[i].compareTo(LF) == 0) {
+ if (cr && lf && cr2) {
+ compressedString.append(stringArray[i]);
+ } else if (lf) {
+ if (nonSpace) {
+ compressedString.append(LF);
+ nonSpace = false;
+ }
+ compressedString.append(stringArray[i]);
+ } else
+ lf = true;
+ } else if ((stringArray[i].compareTo(SPACE) != 0) && (stringArray[i].compareTo(TAB) != 0) && (stringArray[i].compareTo(FF) != 0)) {
+ if (compressedString.length() > 0)
+ compressedString.append(SPACE);
+ compressedString.append(stringArray[i]);
+
+ cr = false;
+ lf = false;
+ cr2 = false;
+ nonSpace = true;
+ }
+ }
+ }
+
+ return compressedString.toString();
+ }
+
+ protected boolean firstStructuredDocumentRegionContainsLineDelimiters(XMLNode node) {
+ boolean result = false;
+
+ if (node != null) {
+ IStructuredDocumentRegion firstStructuredDocumentRegion = node.getFirstStructuredDocumentRegion();
+ if (firstStructuredDocumentRegion != null && firstStructuredDocumentRegion.getText() != null) {
+ String firstStructuredDocumentRegionText = firstStructuredDocumentRegion.getText();
+ result = StringUtils.containsLineDelimiter(firstStructuredDocumentRegionText);
+ }
+ }
+
+ return result;
+ }
+
+ public void format(Node node) {
+ IStructuredFormatContraints formatContraints = getFormatContraints();
+
+ format(node, formatContraints);
+ }
+
+ public void format(Node node, IStructuredFormatContraints formatContraints) {
+ if (formatContraints.getFormatWithSiblingIndent())
+ formatContraints.setCurrentIndent(getSiblingIndent(node));
+
+ if (node instanceof XMLNode)
+ formatNode((XMLNode) node, formatContraints);
+ }
+
+ protected void formatIndentationAfterNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null) {
+ XMLNode nextSibling = (XMLNode) node.getNextSibling();
+ IStructuredDocument doc = node.getModel().getStructuredDocument();
+ int line = doc.getLineOfOffset(node.getEndOffset());
+ String lineDelimiter = doc.getLineDelimiter();
+ try {
+ lineDelimiter = doc.getLineDelimiter(line);
+ if (lineDelimiter == null)
+ lineDelimiter = ""; //$NON-NLS-1$
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+ String tagName = node.getNodeName();
+
+ if (node.getParentNode() != null) {
+ if (node.getParentNode().getNodeType() == Node.DOCUMENT_NODE)
+ if (nextSibling != null)
+ if (nextSibling.getNodeType() == Node.TEXT_NODE)
+ getFormatter(nextSibling).format(nextSibling, formatContraints);
+ else if (nextSibling.getNodeType() == Node.COMMENT_NODE) {
+ // do nothing
+ } else {
+ String lineIndent = formatContraints.getCurrentIndent();
+ insertAfterNode(node, lineDelimiter + lineIndent);
+ }
+ else {
+ }
+
+ else if (nextSibling != null)
+ if (nextSibling.getNodeType() == Node.TEXT_NODE)
+ getFormatter(nextSibling).format(nextSibling, formatContraints);
+ else if (nextSibling.getNodeType() == Node.COMMENT_NODE) {
+ // do nothing
+ } else {
+ String lineIndent = formatContraints.getCurrentIndent();
+ insertAfterNode(node, lineDelimiter + lineIndent);
+ }
+ else {
+ XMLNode indentNode = getParentIndentNode(node);
+ String lineIndent = getNodeIndent(indentNode);
+ XMLNode lastChild = getDeepestChildNode(node);
+ boolean clearAllBlankLines = formatContraints.getClearAllBlankLines();
+
+ if (lastChild != null) {
+ if ((lastChild.getNodeType() == Node.TEXT_NODE) && (lastChild.getNodeValue().endsWith(lineDelimiter + lineIndent))) {
+ // this text node already ends with the requested
+ // indentation
+ }
+
+ else if ((lastChild.getNodeType() == Node.TEXT_NODE) && (lastChild.getNodeValue() != null && lastChild.getNodeValue().endsWith(lineDelimiter)))
+ if (clearAllBlankLines) {
+ replaceNodeValue(lastChild, lineDelimiter + lineIndent);
+ } else {
+ // append indentation
+ insertAfterNode(lastChild, lineIndent);
+ }
+ else if (lastChild.getNodeType() == Node.TEXT_NODE)
+ if (lastChild.getNodeValue().length() == 0) {
+ // replace
+ replaceNodeValue(lastChild, lineDelimiter + lineIndent);
+ } else {
+ // append indentation
+ insertAfterNode(lastChild, lineDelimiter + lineIndent);
+ }
+ else {
+ // append indentation
+ insertAfterNode(lastChild, lineDelimiter + lineIndent);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected void formatIndentationBeforeNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null) {
+ XMLNode previousSibling = (XMLNode) node.getPreviousSibling();
+ IStructuredDocument doc = node.getModel().getStructuredDocument();
+ int line = doc.getLineOfOffset(node.getStartOffset());
+ String lineDelimiter = doc.getLineDelimiter();
+ try {
+ if (line > 0) {
+ lineDelimiter = doc.getLineDelimiter(line - 1);
+ if (lineDelimiter == null)
+ lineDelimiter = ""; //$NON-NLS-1$
+ }
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+ String lineIndent = formatContraints.getCurrentIndent();
+ String tagName = node.getNodeName();
+
+ if (node.getParentNode() != null) {
+ if (node.getParentNode().getNodeType() == Node.DOCUMENT_NODE) {
+ if (previousSibling != null)
+ if (previousSibling.getNodeType() == Node.TEXT_NODE)
+ getFormatter(previousSibling).format(previousSibling, formatContraints);
+ else {
+ insertBeforeNode(node, lineDelimiter + lineIndent);
+ }
+ } else {
+ if (previousSibling == null || previousSibling.getNodeType() != Node.TEXT_NODE) {
+ // 261968 - formatting tag without closing bracket:
+ // <t1><t1
+ // 265673 - Null ptr in formatIndentationBeforeNode
+ int prevEndNodeOffset = -1;
+ int prevEndRegionOffset = -1;
+ if (previousSibling != null) {
+ prevEndNodeOffset = previousSibling.getEndOffset();
+ IStructuredDocumentRegion endRegion = previousSibling.getEndStructuredDocumentRegion();
+ if (endRegion != null) {
+ prevEndRegionOffset = endRegion.getTextEndOffset();
+ }
+ }
+ if ((previousSibling == null) || (prevEndNodeOffset != -1 && prevEndNodeOffset == prevEndRegionOffset)) {
+ insertBeforeNode(node, lineDelimiter + lineIndent);
+ }
+
+ } else {
+ if (previousSibling.getNodeValue().length() == 0) {
+ // replace
+ replaceNodeValue(previousSibling, lineDelimiter + lineIndent);
+ } else {
+ // append indentation
+ if (!previousSibling.getNodeValue().endsWith(lineDelimiter + lineIndent)) {
+ if (previousSibling.getNodeValue().endsWith(lineDelimiter)) {
+ insertAfterNode(previousSibling, lineIndent);
+ } else
+ getFormatter(previousSibling).format(previousSibling, formatContraints);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null && (fProgressMonitor == null || !fProgressMonitor.isCanceled())) {
+ // format indentation before node
+ formatIndentationBeforeNode(node, formatContraints);
+
+ // format indentation after node
+ formatIndentationAfterNode(node, formatContraints);
+ }
+ }
+
+ /**
+ * This method will compute the correct indentation after this node
+ * depending on the indentations of its sibling nodes and parent node. Not
+ * needed anymore?
+ */
+ protected void formatTrailingText(XMLNode node, IStructuredFormatContraints formatContraints) {
+ String lineDelimiter = node.getModel().getStructuredDocument().getLineDelimiter();
+ String lineIndent = formatContraints.getCurrentIndent();
+ String parentLineIndent = getNodeIndent(node.getParentNode());
+ boolean clearAllBlankLines = formatContraints.getClearAllBlankLines();
+
+ if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE)) {
+ XMLNode nextSibling = (XMLNode) node.getNextSibling();
+ if ((nextSibling != null) && (nextSibling.getNodeType() == Node.TEXT_NODE)) {
+ String nextSiblingText = nextSibling.getNodeValue();
+ if (nextSibling.getNextSibling() == null)
+ if ((nextSibling.getParentNode().getNodeType() == Node.DOCUMENT_NODE) && (nextSiblingText.trim().length() == 0))
+ // delete spaces at the end of the document
+ replaceNodeValue(nextSibling, EMPTY_STRING);
+ else
+ // replace the text node with parent indentation
+ replaceNodeValue(nextSibling, lineDelimiter + parentLineIndent);
+ else
+ // replace the text node with indentation
+ replaceNodeValue(nextSibling, lineDelimiter + lineIndent);
+ } else {
+ if (nextSibling == null) {
+ lineIndent = parentLineIndent;
+
+ if (node.getParentNode().getNodeType() != Node.DOCUMENT_NODE)
+ if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter + lineIndent))) {
+ // this text node already ends with the requested
+ // indentation
+ }
+
+ else if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter)))
+ if (clearAllBlankLines)
+ replaceNodeValue(node, lineDelimiter + lineIndent);
+ else
+ // append indentation
+ insertAfterNode(node, lineIndent);
+ else if (node.getNodeType() == Node.TEXT_NODE)
+ if (node.getNodeValue().length() == 0)
+ // replace
+ replaceNodeValue(node, lineDelimiter + lineIndent);
+ else
+ // append indentation
+ if (!node.getNodeValue().endsWith(lineDelimiter + lineIndent))
+ if (node.getNodeValue().endsWith(lineDelimiter))
+ insertAfterNode(node, lineIndent);
+ else
+ insertAfterNode(node, lineDelimiter + lineIndent);
+ else
+ replaceNodeValue(node, lineDelimiter + lineIndent);
+ } else {
+ if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter + lineIndent))) {
+ // this text node already ends with the requested
+ // indentation
+ }
+
+ else if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter)))
+ if (clearAllBlankLines)
+ replaceNodeValue(node, lineDelimiter + lineIndent);
+ else
+ // append indentation
+ insertAfterNode(node, lineIndent);
+ else if (node.getNodeType() == Node.TEXT_NODE)
+ if (node.getNodeValue().length() == 0)
+ // replace
+ replaceNodeValue(node, lineDelimiter + lineIndent);
+ else
+ // append indentation
+ insertAfterNode(node, lineDelimiter + lineIndent);
+ else
+ // append indentation
+ insertAfterNode(node, lineDelimiter + lineIndent);
+ }
+ }
+ }
+ }
+
+ protected String getCompressedNodeText(XMLNode node, IStructuredFormatContraints formatContraints) {
+ return compressSpaces(getNodeText(node), formatContraints);
+ }
+
+ protected XMLNode getDeepestChildNode(XMLNode node) {
+ XMLNode result = null;
+ XMLNode lastChild = (XMLNode) node.getLastChild();
+
+ if (lastChild == null)
+ result = node;
+ else {
+ result = getDeepestChildNode(lastChild);
+
+ if ((result.getNodeType() == Node.TEXT_NODE || result.getNodeType() == Node.COMMENT_NODE) && !isEndTagMissing(node))
+ result = node;
+ }
+
+ return result;
+ }
+
+ public IStructuredFormatContraints getFormatContraints() {
+ if (fFormatContraints == null) {
+ fFormatContraints = new StructuredFormatContraints();
+
+ fFormatContraints.setClearAllBlankLines(getFormatPreferences().getClearAllBlankLines());
+ }
+
+ return fFormatContraints;
+ }
+
+ public IStructuredFormatPreferences getFormatPreferences() {
+ if (fFormatPreferences == null) {
+ fFormatPreferences = new StructuredFormatPreferencesXML();
+
+ Preferences preferences = getModelPreferences();
+ if (preferences != null) {
+ fFormatPreferences.setLineWidth(preferences.getInt(CommonModelPreferenceNames.LINE_WIDTH));
+ ((IStructuredFormatPreferencesXML) fFormatPreferences).setSplitMultiAttrs(preferences.getBoolean(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS));
+ fFormatPreferences.setClearAllBlankLines(preferences.getBoolean(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES));
+
+ if (preferences.getBoolean(CommonModelPreferenceNames.INDENT_USING_TABS))
+ fFormatPreferences.setIndent("\t"); //$NON-NLS-1$
+ else {
+ int tabWidth = getModelManagerPlugin().getPluginPreferences().getInt(CommonModelPreferenceNames.TAB_WIDTH);
+ String indent = ""; //$NON-NLS-1$
+ for (int i = 0; i < tabWidth; i++) {
+ indent += " "; //$NON-NLS-1$
+ }
+ fFormatPreferences.setIndent(indent);
+ }
+ }
+ }
+
+ return fFormatPreferences;
+ }
+
+ protected IStructuredFormatter getFormatter(XMLNode node) {
+ // 262135 - NPE during format of empty document
+ if (node == null)
+ return null;
+
+ short nodeType = ((Node) node).getNodeType();
+ IStructuredFormatter formatter = null;
+ switch (nodeType) {
+ case Node.ELEMENT_NODE : {
+ formatter = new ElementNodeFormatter();
+ break;
+ }
+ case Node.TEXT_NODE : {
+ if (node instanceof CDATASectionImpl)
+ formatter = new NodeFormatter();
+ else
+ formatter = new TextNodeFormatter();
+ break;
+ }
+ case Node.COMMENT_NODE : {
+ formatter = new CommentNodeFormatter();
+ break;
+ }
+ case Node.PROCESSING_INSTRUCTION_NODE : {
+ formatter = new NodeFormatter();
+ break;
+ }
+ case Node.DOCUMENT_NODE : {
+ formatter = new DocumentNodeFormatter();
+ break;
+ }
+ default : {
+ formatter = new NodeFormatter();
+ }
+ }
+
+ // init fomatter
+ formatter.setFormatPreferences(getFormatPreferences());
+ formatter.setProgressMonitor(fProgressMonitor);
+
+ return formatter;
+ }
+
+ protected int getIndentationLength(String indent) {
+ // TODO Kit : The calculation of IndentationLength is not correct
+ // here.
+ // nodeIndentation may contain tabs. Multiply by 4 temporarily to get
+ // approx. width.
+ // Need to re-work.
+
+ int indentationLength = 0;
+
+ for (int i = 0; i < indent.length(); i++) {
+ if (indent.substring(i, i + 1).compareTo(TAB) == 0)
+ indentationLength += 4;
+ else
+ indentationLength++;
+ }
+
+ return indentationLength;
+ }
+
+ private IModelManagerPlugin getModelManagerPlugin() {
+
+ IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID);
+ return plugin;
+ }
+
+ protected Preferences getModelPreferences() {
+ return XMLModelPlugin.getDefault().getPluginPreferences();
+ }
+
+ /**
+ * This method will find the indentation for this node. It will search
+ * backwards starting from the beginning of the node until a character
+ * other than a space or a tab is found. If this node is null or it's a
+ * document node or it's a first level node (node's parent is a document
+ * node) the default empty string will be returned as the indentation.
+ */
+ protected String getNodeIndent(Node node) {
+ String result = EMPTY_STRING;
+
+ if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE) && (node.getParentNode() != null) && (node.getParentNode().getNodeType() != Node.DOCUMENT_NODE)) {
+ XMLNode siblingTextNode = (XMLNode) node.getPreviousSibling();
+ if ((siblingTextNode != null) && (siblingTextNode.getNodeType() == Node.TEXT_NODE)) {
+ // find the indentation
+ String siblingText = siblingTextNode.getNodeValue();
+ int siblingTextLength = siblingText.length();
+ if ((siblingText != null) && (siblingTextLength > 0) && ((siblingText.charAt(siblingTextLength - 1) == SPACE_CHAR) || (siblingText.charAt(siblingTextLength - 1) == TAB_CHAR))) {
+ int searchIndex = siblingTextLength - 1;
+ while ((searchIndex >= 0) && ((siblingText.charAt(searchIndex) == SPACE_CHAR) || (siblingText.charAt(searchIndex) == TAB_CHAR)))
+ searchIndex--;
+
+ if (searchIndex < siblingTextLength)
+ result = siblingText.substring(searchIndex + 1, siblingTextLength);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ protected String getNodeName(XMLNode node) {
+ return node.getNodeName();
+ }
+
+ protected String getNodeText(XMLNode node) {
+ String text = null;
+
+ if ((node instanceof org.eclipse.wst.xml.core.internal.document.CharacterDataImpl) && !(node instanceof org.eclipse.wst.xml.core.internal.document.CommentImpl) && !(node instanceof org.eclipse.wst.xml.core.internal.document.CDATASectionImpl) && !isJSPTag(node))
+ text = ((org.eclipse.wst.xml.core.internal.document.CharacterDataImpl) node).getSource();
+ else
+ text = node.getFirstStructuredDocumentRegion().getText();
+
+ return text;
+ }
+
+ protected XMLNode getParentIndentNode(XMLNode node) {
+ XMLNode result = null;
+ XMLNode parentNode = (XMLNode) node.getParentNode();
+
+ if (parentNode.getNodeType() == Node.DOCUMENT_NODE)
+ result = parentNode;
+ else {
+ ITextRegion region = parentNode.getLastStructuredDocumentRegion().getFirstRegion();
+ if (region.getType() == XMLRegionContext.XML_END_TAG_OPEN)
+ result = parentNode;
+ else
+ result = getParentIndentNode(parentNode);
+ }
+
+ return result;
+ }
+
+ /**
+ * This method will find the indentation for a node sibling to this node.
+ * It will try to find a sibling node before this node first. If there is
+ * no sibling node before this node, it will try to find a sibling node
+ * after this node. If still not found, we will check if this node is
+ * already indented from its parent. If yes, this node's indentation will
+ * be used. Otherwise, the parent node's indentation plus one indentation
+ * will be used. If this node is null or it's a document node or it's a
+ * first level node (node's parent is a document node) the default empty
+ * string will be returned as the indentation.
+ */
+ protected String getSiblingIndent(Node node) {
+ String result = EMPTY_STRING;
+
+ if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE) && (node.getParentNode() != null) && (node.getParentNode().getNodeType() != Node.DOCUMENT_NODE)) {
+ // find the text node before the previous non-text sibling
+ // if that's not found, we will try the text node before the next
+ // non-text sibling
+ XMLNode sibling = (XMLNode) node.getPreviousSibling();
+ while ((sibling != null) && (sibling.getNodeType() == Node.TEXT_NODE || sibling.getNodeType() == Node.COMMENT_NODE)) {
+ if (sibling.getNodeType() == Node.COMMENT_NODE && sibling.getPreviousSibling() != null && sibling.getPreviousSibling().getNodeType() == Node.TEXT_NODE && StringUtils.containsLineDelimiter(sibling.getPreviousSibling().getNodeValue()))
+ break;
+ sibling = (XMLNode) sibling.getPreviousSibling();
+ }
+ if (sibling == null) {
+ sibling = (XMLNode) node.getNextSibling();
+ while ((sibling != null) && (sibling.getNodeType() == Node.TEXT_NODE))
+ sibling = (XMLNode) sibling.getNextSibling();
+ }
+ String singleIndent = getFormatPreferences().getIndent();
+ String parentLineIndent = getNodeIndent(node.getParentNode());
+
+ if (sibling != null) {
+ String siblingIndent = getNodeIndent(sibling);
+ if (siblingIndent.length() > 0)
+ result = siblingIndent;
+ else {
+ String nodeIndent = getNodeIndent(node);
+ if (nodeIndent.length() > parentLineIndent.length())
+ // this node is indented from its parent, its
+ // indentation will be used
+ result = nodeIndent;
+ else
+ result = parentLineIndent + singleIndent;
+ }
+ } else {
+ String nodeIndent = getNodeIndent(node);
+ if (nodeIndent.length() > parentLineIndent.length())
+ // this node is indented from its parent, its indentation
+ // will be used
+ result = nodeIndent;
+ else
+ result = parentLineIndent + singleIndent;
+ }
+ }
+
+ return result;
+ }
+
+ protected void insertAfterNode(XMLNode node, String string) {
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+
+ int offset = node.getEndOffset();
+ int length = 0;
+
+ // 261968 - formatting tag without closing bracket: <t1><t1
+ if (node.getEndStructuredDocumentRegion() != null) {
+ offset = node.getEndStructuredDocumentRegion().getTextEndOffset();
+ length = node.getEndOffset() - offset;
+ }
+ replace(structuredDocument, offset, length, string);
+ }
+
+ protected void insertBeforeNode(XMLNode node, String string) {
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+
+ replace(structuredDocument, node.getStartOffset(), 0, string);
+ }
+
+ /**
+ * 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(IStructuredFormatter.class);
+ }
+
+ protected boolean isEndTagMissing(XMLNode node) {
+ boolean result = false;
+
+ if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE) && !isJSPTag(node)) {
+ IStructuredDocumentRegion startTagStructuredDocumentRegion = node.getFirstStructuredDocumentRegion();
+ IStructuredDocumentRegion endTagStructuredDocumentRegion = node.getLastStructuredDocumentRegion();
+
+ ITextRegion startTagNameRegion = null;
+ if (startTagStructuredDocumentRegion.getRegions().size() > 1)
+ startTagNameRegion = startTagStructuredDocumentRegion.getRegions().get(1);
+ ITextRegion endTagNameRegion = null;
+ if (endTagStructuredDocumentRegion.getRegions().size() > 1)
+ endTagNameRegion = endTagStructuredDocumentRegion.getRegions().get(1);
+
+ ITextRegionList startTagRegions = startTagStructuredDocumentRegion.getRegions();
+ if (startTagNameRegion == endTagNameRegion && startTagNameRegion != null && (startTagRegions.get(0)).getType() != XMLRegionContext.XML_END_TAG_OPEN && (startTagRegions.get(startTagRegions.size() - 1).getType()) != XMLRegionContext.XML_EMPTY_TAG_CLOSE)
+ // end tag missing
+ result = true;
+ }
+
+ return result;
+ }
+
+ protected boolean isJSPTag(XMLNode node) {
+ boolean result = false;
+
+ IStructuredDocumentRegion flatNode = node.getFirstStructuredDocumentRegion();
+ // in some cases, the nodes exists, but hasn't been associated with
+ // a flatnode yet (the screen updates can be initiated on a different
+ // thread,
+ // so the request for a flatnode can come in before the node is fully
+ // formed.
+ // if the flatnode is null, we'll just allow the defaults to apply.
+ // (html adapter in this case).
+ if (flatNode != null) {
+ String flatNodeType = flatNode.getType();
+ if ((flatNodeType == XMLJSPRegionContexts.JSP_CONTENT) || (flatNodeType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE) || (flatNodeType == XMLJSPRegionContexts.JSP_DIRECTIVE_NAME) || (flatNodeType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_CLOSE)) {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+
+ protected boolean nodeHasSiblings(XMLNode node) {
+ return (node.getPreviousSibling() != null) || (node.getNextSibling() != null);
+ }
+
+ /**
+ * Node changed. No format should be performed automatically.
+ */
+ public void notifyChanged(org.eclipse.wst.sse.core.INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ }
+
+ protected void removeRegionSpaces(XMLNode node, IStructuredDocumentRegion flatNode, ITextRegion region) {
+ if ((region != null) && (region instanceof ContextRegion || region instanceof TagNameRegion) && (flatNode.getEndOffset(region) > flatNode.getTextEndOffset(region))) {
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+
+ replace(structuredDocument, flatNode.getTextEndOffset(region), flatNode.getEndOffset(region) - flatNode.getTextEndOffset(region), EMPTY_STRING);
+ }
+ }
+
+ /**
+ * This method will replace the string at offset and length with a new
+ * string. If the string to be replaced is the same as the new string, the
+ * string will not be replaced.
+ */
+ protected void replace(IStructuredDocument structuredDocument, int offset, int length, String string) {
+ try {
+ String structuredDocumentString = structuredDocument.get(offset, length);
+ if (structuredDocumentString.compareTo(string) != 0)
+ structuredDocument.replaceText(structuredDocument, offset, length, string);
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+ }
+
+ /**
+ * This method will replace the node value with a new string. If the node
+ * value to be replaced is the same as the new string, the node value will
+ * not be replaced.
+ */
+ protected void replaceNodeValue(XMLNode node, String string) {
+ XMLModel structuredModel = node.getModel();
+ IStructuredDocument structuredDocument = structuredModel.getStructuredDocument();
+ int offset = node.getStartOffset();
+ int length = node.getEndOffset() - node.getStartOffset();
+
+ try {
+ String structuredDocumentString = structuredDocument.get(offset, length);
+ if (structuredDocumentString.compareTo(string) != 0)
+ replace(structuredDocument, offset, length, string);
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+ }
+
+ public void setFormatPreferences(IStructuredFormatPreferences formatPreferences) {
+ fFormatPreferences = formatPreferences;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.wst.sse.core.format.IStructuredFormatter#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void setProgressMonitor(IProgressMonitor monitor) {
+ fProgressMonitor = monitor;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java
new file mode 100644
index 0000000000..079ae41c29
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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.format;
+
+import org.eclipse.wst.sse.core.format.StructuredFormatPreferences;
+
+public class StructuredFormatPreferencesXML extends StructuredFormatPreferences implements IStructuredFormatPreferencesXML {
+ private boolean fSplitMultiAttrs;
+
+ public boolean getSplitMultiAttrs() {
+ return fSplitMultiAttrs;
+ }
+
+ public void setSplitMultiAttrs(boolean splitMultiAttrs) {
+ fSplitMultiAttrs = splitMultiAttrs;
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java
new file mode 100644
index 0000000000..1d428e9de2
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * 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.format;
+
+import java.util.Vector;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException;
+import org.eclipse.wst.sse.core.format.IStructuredFormatContraints;
+import org.eclipse.wst.sse.core.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.util.StringUtils;
+import org.eclipse.wst.xml.core.document.XMLNode;
+import org.w3c.dom.Node;
+
+
+public class TextNodeFormatter extends NodeFormatter {
+ protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) {
+ if (node != null) {
+ IStructuredDocument doc = node.getModel().getStructuredDocument();
+ int line = doc.getLineOfOffset(node.getStartOffset());
+ String lineDelimiter = doc.getLineDelimiter();
+ try {
+ lineDelimiter = doc.getLineDelimiter(line);
+ if (lineDelimiter == null)
+ lineDelimiter = ""; //$NON-NLS-1$
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+ int lineWidth = getFormatPreferences().getLineWidth();
+ XMLNode parentNode = (XMLNode) node.getParentNode();
+ XMLNode nextSibling = (XMLNode) node.getNextSibling();
+ String nodeIndentation = formatContraints.getCurrentIndent();
+
+ // compute current available line width
+ int currentAvailableLineWidth = 0;
+ try {
+ int nodeNameOffset = node.getStartOffset();
+ int lineOffset = node.getStructuredDocument().getLineInformationOfOffset(nodeNameOffset).getOffset();
+ String text = node.getStructuredDocument().get(lineOffset, nodeNameOffset - lineOffset);
+ int usedWidth = getIndentationLength(text);
+ currentAvailableLineWidth = getFormatPreferences().getLineWidth() - usedWidth;
+ } catch (BadLocationException exception) {
+ throw new SourceEditingRuntimeException(exception);
+ }
+
+ String compressedText = getCompressedNodeText(node, formatContraints);
+
+ if (((compressedText.length() <= (currentAvailableLineWidth - node.getParentNode().getNodeName().length() - 3) && !StringUtils.containsLineDelimiter(compressedText)) && (!nodeHasSiblings(node) || (!StringUtils.containsLineDelimiter(node.getNodeValue()) && node.getNextSibling() != null && node.getNextSibling().getNodeType() == Node.COMMENT_NODE && !StringUtils.containsLineDelimiter(node.getNextSibling().getNodeValue()))) && !firstStructuredDocumentRegionContainsLineDelimiters((XMLNode) node.getParentNode())) || node.getStartStructuredDocumentRegion().getStartOffset() == 0) {
+ // enough space
+ // and text has no line delimiters
+ // and (node has no siblings or followed by inline comment)
+ // and
+ // parentFirstStructuredDocumentRegionContainsLineDelimiters
+
+ if (isEndTagMissing(parentNode)) {
+ parentNode = (XMLNode) parentNode.getParentNode();
+ while (isEndTagMissing(parentNode))
+ parentNode = (XMLNode) parentNode.getParentNode();
+
+ // add parent's indentation to end
+ nodeIndentation = getNodeIndent(parentNode);
+
+ if (!compressedText.endsWith(lineDelimiter + nodeIndentation)) {
+ compressedText = StringUtils.appendIfNotEndWith(compressedText, lineDelimiter);
+ compressedText = StringUtils.appendIfNotEndWith(compressedText, nodeIndentation);
+ }
+ }
+
+ if ((parentNode != null) && (parentNode.getNodeType() == Node.DOCUMENT_NODE) && (node.getNodeValue().length() > 0) && (node.getNodeValue().trim().length() == 0) && ((node.getPreviousSibling() == null) || (node.getNextSibling() == null)))
+ // delete spaces at the beginning or end of the document
+ compressedText = EMPTY_STRING;
+
+ replaceNodeValue(node, compressedText);
+ } else {
+ // not enough space, need to reflow text
+
+ currentAvailableLineWidth = lineWidth - getIndentationLength(nodeIndentation);
+ Vector vector = reflowText(compressedText, currentAvailableLineWidth);
+ int vectorSize = vector.size();
+ String reflowedText = new String();
+
+ for (int i = 0; i < vectorSize; i++) {
+ if (((String) vector.elementAt(i)).trim().length() > 0)
+ reflowedText = reflowedText + lineDelimiter + nodeIndentation + (String) vector.elementAt(i);
+ else
+ reflowedText = reflowedText + lineDelimiter;
+ }
+
+ if (node.getNextSibling() == null) {
+ if (isEndTagMissing(parentNode)) {
+ // don't add indentation to end if parent end tag is
+ // missing
+ }
+
+ else {
+ // add parent's indentation to end
+ nodeIndentation = getNodeIndent(parentNode);
+
+ if (!reflowedText.endsWith(lineDelimiter + nodeIndentation)) {
+ reflowedText = StringUtils.appendIfNotEndWith(reflowedText, lineDelimiter);
+ reflowedText = StringUtils.appendIfNotEndWith(reflowedText, nodeIndentation);
+ }
+ }
+ } else {
+ if (!reflowedText.endsWith(lineDelimiter + nodeIndentation)) {
+ // not already ended with the expected indentation
+
+ if (node.getNextSibling().getNodeType() == Node.COMMENT_NODE) {
+ // add indentation to end if
+ // currentTextEndsWithLineDelimiter
+ // or followed by multiLineComment
+
+ String nodeText = getNodeText(node);
+ int indexOfLastLineDelimiter = StringUtils.indexOfLastLineDelimiter(nodeText);
+ boolean currentTextEndsWithLineDelimiter = indexOfLastLineDelimiter != -1;
+ if (currentTextEndsWithLineDelimiter) {
+ // no more non blank character after the last
+ // line delimiter
+ currentTextEndsWithLineDelimiter = StringUtils.indexOfNonblank(nodeText, indexOfLastLineDelimiter) == -1;
+ }
+
+ String nodeValue = node.getNextSibling().getNodeValue();
+ boolean multiLineComment = StringUtils.containsLineDelimiter(nodeValue);
+
+ if (currentTextEndsWithLineDelimiter || multiLineComment) {
+ reflowedText = StringUtils.appendIfNotEndWith(reflowedText, lineDelimiter);
+ reflowedText = StringUtils.appendIfNotEndWith(reflowedText, nodeIndentation);
+ }
+ } else {
+ // not a comment, just add add indentation to end
+ reflowedText = StringUtils.appendIfNotEndWith(reflowedText, lineDelimiter);
+ reflowedText = StringUtils.appendIfNotEndWith(reflowedText, nodeIndentation);
+ }
+ }
+ }
+
+ replaceNodeValue(node, reflowedText);
+ }
+
+ }
+ }
+
+ protected Vector reflowText(String text, int availableWidth) {
+ String[] stringArray = null;
+ boolean clearAllBlankLines = getFormatPreferences().getClearAllBlankLines();
+
+ if (clearAllBlankLines)
+ stringArray = StringUtils.asArray(text);
+ else
+ stringArray = StringUtils.asArray(text, DELIMITERS, true);
+
+ Vector output = new Vector();
+ if ((stringArray != null) && (stringArray.length > 0)) {
+ StringBuffer buffer = new StringBuffer();
+ if (stringArray[0].compareTo(CR) != 0)
+ buffer.append(stringArray[0]);
+ int bufferLength = stringArray[0].toString().length();
+ boolean cr = stringArray[0].compareTo(CR) == 0;
+
+ for (int i = 1; i < stringArray.length; i++) {
+ String eachString = stringArray[i];
+ if ((eachString.compareTo(SPACE) != 0) && (eachString.compareTo(TAB) != 0) && (eachString.compareTo(FF) != 0)) {
+ if ((bufferLength + 1 + eachString.length() > availableWidth) || (eachString.compareTo(CR) == 0) || (eachString.compareTo(LF) == 0)) {
+ if ((eachString.compareTo(LF) == 0) && cr) {
+ // do nothing
+ } else {
+ output.add(buffer.toString());
+ buffer = new StringBuffer();
+ bufferLength = 0;
+ }
+ cr = eachString.compareTo(CR) == 0;
+ } else if (buffer.toString().trim().length() > 0) {
+ buffer.append(SPACE);
+ bufferLength++;
+ }
+ if ((eachString.compareTo(CR) != 0) && (eachString.compareTo(LF) != 0)) {
+ buffer.append(eachString);
+ bufferLength = bufferLength + eachString.length();
+ }
+ }
+ }
+ output.add(buffer.toString());
+ } else
+ output.add(text);
+
+ return output;
+ }
+}
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