diff options
author | Carsten Hiesserich | 2013-08-28 16:14:19 +0000 |
---|---|---|
committer | Carsten Hiesserich | 2013-09-08 10:50:27 +0000 |
commit | dea80070d191a4e99ace9b25596fde02f8fef563 (patch) | |
tree | aa90b1abb9a43b719c7d834421be1aa68926483f | |
parent | b984d14a2316a6662083062ad397234b51a3f2ee (diff) | |
download | org.eclipse.mylyn.docs.vex-dea80070d191a4e99ace9b25596fde02f8fef563.tar.gz org.eclipse.mylyn.docs.vex-dea80070d191a4e99ace9b25596fde02f8fef563.tar.xz org.eclipse.mylyn.docs.vex-dea80070d191a4e99ace9b25596fde02f8fef563.zip |
bug 251955: Basic support for processing instructions
Added read/write support for processing insctructions, so they don't get
lost when editing a document with VEX.
To show the PI's in the layout will be a seperate step.
Change-Id: I20a1fd4d8ff8199038b6d8ddbf1d268aff1be57b
Signed-off-by: Carsten Hiesserich <carsten.hie@gmail.com>
22 files changed, 776 insertions, 67 deletions
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java index 4f5fe1b2..2def0cb8 100644 --- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java +++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/DeepCopyTest.java @@ -252,6 +252,32 @@ public class DeepCopyTest { assertEquals("ns2", copiedChild.getDeclaredNamespacePrefixes().iterator().next());
}
+ @Test
+ public void givenOneParentWithProcessingInstruction_shouldCopyParentAndProcessingInstruction() throws Exception {
+ final GapContent content = new GapContent(10);
+ content.insertTagMarker(0);
+ content.insertTagMarker(0);
+ content.insertTagMarker(0);
+ content.insertTagMarker(0);
+ final Element parent = new Element("parent");
+ parent.associate(content, content.getRange());
+
+ final ProcessingInstruction pi = new ProcessingInstruction("PI");
+ pi.associate(content, new ContentRange(1, 2));
+ content.insertText(2, "test= 1");
+
+ parent.addChild(pi);
+
+ final DeepCopy deepCopy = new DeepCopy(parent);
+ final Element copiedParent = (Element) deepCopy.getNodes().get(0);
+ final List<? extends INode> copiedChildren = copiedParent.children().asList();
+
+ assertEquals(1, copiedChildren.size());
+ assertTrue("Expecting the copied processing instruction", copiedChildren.get(0) instanceof ProcessingInstruction);
+ assertEquals("Data should be copied", pi.getText(), copiedChildren.get(0).getText());
+ assertEquals("Target should be copied", pi.getTarget(), ((ProcessingInstruction) copiedChildren.get(0)).getTarget());
+ }
+
private static void assertNodeIsAssociatedElementWithText(final String expectedText, final INode actualNode) {
assertTrue(actualNode.isAssociated());
assertTrue(actualNode instanceof Element);
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ProcessingInstructionHandlingTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ProcessingInstructionHandlingTest.java new file mode 100644 index 00000000..4fee0c68 --- /dev/null +++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/L1ProcessingInstructionHandlingTest.java @@ -0,0 +1,161 @@ +/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.internal.dom;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.vex.core.provisional.dom.DocumentValidationException;
+import org.eclipse.vex.core.provisional.dom.IComment;
+import org.eclipse.vex.core.provisional.dom.IDocument;
+import org.eclipse.vex.core.provisional.dom.IElement;
+import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Florian Thienel
+ */
+public class L1ProcessingInstructionHandlingTest {
+
+ private static final QualifiedName VALID_CHILD = new QualifiedName(null, "validChild");
+
+ private IDocument document;
+ private IElement rootElement;
+ private IElement titleElement;
+
+ @Before
+ public void setUp() throws Exception {
+ document = new Document(new QualifiedName(null, "root"));
+ rootElement = document.getRootElement();
+ titleElement = document.insertElement(2, new QualifiedName(null, "title"));
+ }
+
+ @Test
+ public void shouldIndicateValidInsertionPoints() throws Exception {
+ assertFalse(document.canInsertProcessingInstruction(document.getStartOffset(), null));
+ assertTrue(document.canInsertProcessingInstruction(rootElement.getStartOffset(), null));
+ assertTrue(document.canInsertProcessingInstruction(titleElement.getStartOffset(), null));
+ assertTrue(document.canInsertProcessingInstruction(titleElement.getEndOffset(), null));
+ assertTrue(document.canInsertProcessingInstruction(rootElement.getEndOffset(), null));
+ assertTrue(document.canInsertProcessingInstruction(document.getEndOffset(), null));
+ assertFalse(document.canInsertProcessingInstruction(document.getEndOffset() + 1, null));
+ }
+
+ @Test
+ public void shouldInsertProcessingInstructionAtValidInsertionPoint() throws Exception {
+ final IProcessingInstruction pi = document.insertProcessingInstruction(titleElement.getStartOffset(), "pi");
+
+ assertSame(rootElement, pi.getParent());
+ assertTrue(pi.isAssociated());
+ final Iterator<INode> actualChildren = rootElement.children().iterator();
+ assertSame(pi, actualChildren.next());
+ assertSame(titleElement, actualChildren.next());
+ }
+
+ @Test
+ public void shouldInsertTextIntoProcessingInstruction() throws Exception {
+ // text may only be inserted in the processing instruction and in the title element
+ document.setValidator(new DummyValidator() {
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> nodes, final boolean partial) {
+ return "title".equals(element.getLocalName());
+ }
+
+ @Override
+ public boolean isValidSequence(final QualifiedName element, final List<QualifiedName> sequence1, final List<QualifiedName> sequence2, final List<QualifiedName> sequence3,
+ final boolean partial) {
+ return "title".equals(element.getLocalName());
+ }
+ });
+ final IProcessingInstruction pi = document.insertProcessingInstruction(titleElement.getStartOffset(), "pi");
+ document.insertText(pi.getEndOffset(), "data=test");
+
+ assertEquals("data=test", pi.getText());
+ assertEquals("pi", pi.getTarget());
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotAcceptTargetStartingWithXML() throws Exception {
+ document.insertProcessingInstruction(rootElement.getStartOffset(), "XmL");
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotAcceptTargetWithLeadingWhitespace() throws Exception {
+ document.insertProcessingInstruction(rootElement.getStartOffset(), " target");
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotAcceptTargetWithInnerWhitespace() throws Exception {
+ document.insertProcessingInstruction(rootElement.getStartOffset(), "tar get");
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotAcceptEndTagInTarget() throws Exception {
+ document.insertProcessingInstruction(rootElement.getStartOffset(), "tar?>get");
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotInsertEndTagInProcessingInstruction() throws Exception {
+ final IProcessingInstruction pi = document.insertProcessingInstruction(rootElement.getStartOffset(), "");
+ document.insertText(pi.getEndOffset(), "Test?>After");
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotInsertProcessingInstructionAtInvalidInsertionPoint() throws Exception {
+ document.insertProcessingInstruction(document.getStartOffset(), "target");
+ }
+
+ @Test
+ public void shouldInsertProcesingInstructionBeforeRootElement() throws Exception {
+ final IProcessingInstruction pi = document.insertProcessingInstruction(rootElement.getStartOffset(), "pi");
+ final Iterator<INode> actualChildren = document.children().iterator();
+ assertSame(pi, actualChildren.next());
+ assertSame(rootElement, actualChildren.next());
+ assertFalse(actualChildren.hasNext());
+ }
+
+ @Test
+ public void givenInvalidTarget_shouldIndicateInvalidInsertion() throws Exception {
+ assertFalse(document.canInsertProcessingInstruction(titleElement.getStartOffset(), "invalid target"));
+ }
+
+ @Test
+ public void shouldIndicateInvalidInsertionInProcessingInstruction() throws Exception {
+ final IProcessingInstruction pi = document.insertProcessingInstruction(titleElement.getStartOffset(), "pi");
+ assertFalse(document.canInsertProcessingInstruction(pi.getEndOffset(), null));
+ }
+
+ @Test
+ public void shouldIndicateInvalidInsertionInComments() throws Exception {
+ final IComment comment = document.insertComment(titleElement.getStartOffset());
+ assertFalse(document.canInsertProcessingInstruction(comment.getEndOffset(), null));
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotInsertElementInProcessingInstruction() throws Exception {
+ final IProcessingInstruction pi = document.insertProcessingInstruction(titleElement.getStartOffset(), "pi");
+ document.insertElement(pi.getEndOffset(), VALID_CHILD);
+ }
+
+ @Test(expected = DocumentValidationException.class)
+ public void shouldNotInsertProcessingInstructionInProcessingInstruction() throws Exception {
+ final IProcessingInstruction pi = document.insertProcessingInstruction(titleElement.getStartOffset(), "pi");
+ document.insertProcessingInstruction(pi.getEndOffset(), "target");
+ }
+}
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java index 2a36882d..2b6b6fbc 100644 --- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java +++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentReaderTest.java @@ -31,6 +31,7 @@ import org.eclipse.vex.core.provisional.dom.IComment; import org.eclipse.vex.core.provisional.dom.IDocument;
import org.eclipse.vex.core.provisional.dom.IElement;
import org.eclipse.vex.core.provisional.dom.INode;
+import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
import org.eclipse.vex.core.provisional.dom.IText;
import org.eclipse.vex.core.tests.TestResources;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
@@ -171,6 +172,39 @@ public class DocumentReaderTest { }
@Test
+ public void readDocumentWithProcessingInstruction() throws Exception {
+ final DocumentReader reader = new DocumentReader();
+
+ final IDocument document = reader.read(TestResources.get("documentWithProcessingInstr.xml"));
+ final Iterator<INode> documentChildren = document.children().iterator();
+
+ final IProcessingInstruction pi1 = (IProcessingInstruction) documentChildren.next();
+ assertEquals("position=beforeRoot", pi1.getText());
+ assertEquals("pi", pi1.getTarget());
+ assertSame(document.getRootElement(), documentChildren.next());
+ final IProcessingInstruction pi2 = (IProcessingInstruction) documentChildren.next();
+ assertEquals("position=afterRoot", pi2.getText());
+ final IProcessingInstruction pi3 = (IProcessingInstruction) documentChildren.next();
+ assertEquals("Entity references should not be parsed", "<test>", pi3.getText());
+ assertFalse(documentChildren.hasNext());
+
+ final IElement rootElement = document.getRootElement();
+ final Iterator<INode> rootChildren = rootElement.children().iterator();
+
+ final IProcessingInstruction pi4 = (IProcessingInstruction) rootChildren.next();
+ assertEquals("position=begin", pi4.getText());
+
+ rootChildren.next();
+
+ final IElement para = (IElement) rootChildren.next();
+ final IProcessingInstruction pi5 = (IProcessingInstruction) para.children().get(1);
+ assertEquals("position=inline", pi5.getText());
+ assertEquals("Before PI position=inline After PI", para.getText());
+
+ assertFalse(rootChildren.hasNext());
+ }
+
+ @Test
public void shouldNotAddWhitespaceTextNodesInDocumentWithoutDTD() throws Exception {
final DocumentReader reader = new DocumentReader();
final IDocument document = reader.read(TestResources.get("documentWithoutDTD.xml"));
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java index 5c976abb..0e7aa42f 100644 --- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java +++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/io/DocumentWriterTest.java @@ -64,6 +64,11 @@ public class DocumentWriterTest { } @Test + public void testDocumentWithProcessingInstructions() throws Exception { + assertWriteReadCycleWorks(TestResources.get("documentWithProcessingInstr.xml")); + } + + @Test public void writeDocumentFragmentNoWrap() throws Exception { final Document doc = new Document(new QualifiedName(null, "root")); final IElement child1 = doc.insertElement(doc.getRootElement().getEndOffset(), new QualifiedName(null, "child")); diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java index c452102e..0413e424 100644 --- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java +++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/tests/VEXCoreTestSuite.java @@ -35,6 +35,7 @@ import org.eclipse.vex.core.internal.dom.L1CommentHandlingTest; import org.eclipse.vex.core.internal.dom.L1DeletionTests; import org.eclipse.vex.core.internal.dom.L1ElementHandlingTest; import org.eclipse.vex.core.internal.dom.L1FragmentHandlingTest; +import org.eclipse.vex.core.internal.dom.L1ProcessingInstructionHandlingTest; import org.eclipse.vex.core.internal.dom.L1TextHandlingTest; import org.eclipse.vex.core.internal.dom.NamespaceTest; import org.eclipse.vex.core.internal.dom.ParentTest; @@ -67,11 +68,11 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ FilterIteratorTest.class, FirstNIteratorTest.class, AfterNIteratorTest.class, AxisTest.class, NamespaceStackTest.class, NamespaceTest.class, DocumentReaderTest.class, DocumentContentModelTest.class, SchemaValidatorTest.class, CssTest.class, BatikBehaviorTest.class, ContentRangeTest.class, BasicNodeTest.class, ParentTest.class, DocumentTest.class, - L1TextHandlingTest.class, L1CommentHandlingTest.class, L1ElementHandlingTest.class, L1FragmentHandlingTest.class, L1DeletionTests.class, DocumentFragmentTest.class, CopyVisitorTest.class, - DeepCopyTest.class, PropertyTest.class, RuleTest.class, BlockElementBoxTest.class, ImageBoxTest.class, DocumentWriterTest.class, DTDValidatorTest.class, GapContentTest.class, - SpaceNormalizerTest.class, TextWrapperTest.class, TestBlockElementBox.class, TestBlocksInInlines.class, TestDocumentTextBox.class, TestStaticTextBox.class, TableLayoutTest.class, - LayoutTestSuite.class, ListenerListTest.class, DocumentFragmentTransferTest.class, XMLFragmentTest.class, VexWidgetTest.class, L2SimpleEditingTest.class, L2SelectionTest.class, - L2CommentEditingTest.class, L2XmlInsertionTest.class, DocumentEventTest.class, L2StyleSheetTest.class + L1TextHandlingTest.class, L1CommentHandlingTest.class, L1ProcessingInstructionHandlingTest.class, L1ElementHandlingTest.class, L1FragmentHandlingTest.class, L1DeletionTests.class, + DocumentFragmentTest.class, CopyVisitorTest.class, DeepCopyTest.class, PropertyTest.class, RuleTest.class, BlockElementBoxTest.class, ImageBoxTest.class, DocumentWriterTest.class, + DTDValidatorTest.class, GapContentTest.class, SpaceNormalizerTest.class, TextWrapperTest.class, TestBlockElementBox.class, TestBlocksInInlines.class, TestDocumentTextBox.class, + TestStaticTextBox.class, TableLayoutTest.class, LayoutTestSuite.class, ListenerListTest.class, DocumentFragmentTransferTest.class, XMLFragmentTest.class, VexWidgetTest.class, + L2SimpleEditingTest.class, L2SelectionTest.class, L2CommentEditingTest.class, L2XmlInsertionTest.class, DocumentEventTest.class, L2StyleSheetTest.class }) public class VEXCoreTestSuite { diff --git a/org.eclipse.vex.core.tests/testResources/documentWithProcessingInstr.xml b/org.eclipse.vex.core.tests/testResources/documentWithProcessingInstr.xml new file mode 100644 index 00000000..80f2e408 --- /dev/null +++ b/org.eclipse.vex.core.tests/testResources/documentWithProcessingInstr.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?>
+<!DOCTYPE section PUBLIC "-//Eclipse Foundation//DTD Vex Test//EN" "test1.dtd">
+<?pi position=beforeRoot?>
+<section>
+ <?pi position=begin?>
+ <title>Testdocument with Processing Instructions</title>
+ <para>Before PI <?pi position=inline?> After PI</para>
+</section>
+<?pi position=afterRoot?>
+<?pi <test>?>
\ No newline at end of file diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/IValidationResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/IValidationResult.java new file mode 100644 index 00000000..9d604b50 --- /dev/null +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/IValidationResult.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2013 Carsten Hiesserich 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: + * Carsten Hiesserich - initial API and implementation + *******************************************************************************/ +package org.eclipse.vex.core; + +import org.eclipse.core.runtime.IStatus; + +/** + * A VEX specific implementation of the IStatus interface. + * + * @author chi + */ +public interface IValidationResult extends IStatus { + +} diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/ValidationResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/ValidationResult.java new file mode 100644 index 00000000..9845beab --- /dev/null +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/ValidationResult.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2013 Carsten Hiesserich 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: + * Carsten Hiesserich - initial API and implementation + *******************************************************************************/ +package org.eclipse.vex.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.vex.core.internal.VEXCorePlugin; + +public class ValidationResult implements IValidationResult { + + private final String message; + private final int severity; + + private static final IStatus[] emptyStatusArray = new IStatus[0]; + + public static final IValidationResult VALIDATE_OK = new ValidationResult(OK, "ok"); + + /** + * Create a new error result. + * + * @param message + * The validation message. + * @return A new ValidationResult with the given message and severity set to {@link IStatus#ERROR}. + */ + public static IValidationResult error(final String message) { + return new ValidationResult(ERROR, message); + } + + public ValidationResult(final int severity, final String message) { + this.severity = severity; + this.message = message; + } + + @Override + public IStatus[] getChildren() { + return emptyStatusArray; + } + + @Override + public int getCode() { + return 0; + } + + @Override + public Throwable getException() { + return null; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String getPlugin() { + return VEXCorePlugin.ID; + } + + @Override + public int getSeverity() { + return severity; + } + + @Override + public boolean isMultiStatus() { + return false; + } + + @Override + public boolean isOK() { + return severity == OK; + } + + @Override + public boolean matches(final int severityMask) { + return (severity & severityMask) != 0; + } + +} diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/XML.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/XML.java index 11eaf880..d49ad310 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/XML.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/XML.java @@ -10,6 +10,8 @@ *******************************************************************************/
package org.eclipse.vex.core;
+import java.util.regex.Pattern;
+
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.vex.core.internal.dom.Namespace;
@@ -23,6 +25,8 @@ import org.eclipse.vex.core.internal.dom.Namespace; */
public class XML {
+ public static final String VALIDATE_OK = "OK";
+
/**
* The xml:base attribute re-defines the base URI for a part of an XML document, according to the XML Base
* Recommendation.
@@ -40,6 +44,8 @@ public class XML { return c == 0x20 || c == 0x9 || c == 0xD || c == 0xA;
}
+ public static Pattern XML_WHITESPACE_PATTERN = Pattern.compile("[\\u0020\\u0009\\u000d\\u000a]");
+
/**
* Replace runs of XML whitespace (see {@link #isWhitespace}) with a single space. Newlines in the input should be
* normalized before calling this method.
@@ -174,4 +180,47 @@ public class XML { // CR line ending, replace it with a newline
}
}
+
+ /**
+ * Validate the target of an processing instruction.
+ *
+ * @param target
+ * The target String to validate.
+ * @return The IValidationResult. Use {@link IValidationResult#isOK()} to check if there is an error.
+ */
+ public static IValidationResult validateProcessingInstructionTarget(final String target) {
+
+ if (target.isEmpty()) {
+ return ValidationResult.error("Processing instruction target must not be empty");
+ }
+
+ if (XML.XML_WHITESPACE_PATTERN.matcher(target).find()) {
+ return ValidationResult.error("Processing instruction target must not contain whitespace characters");
+ }
+
+ if (target.indexOf("?>") > -1) {
+ return ValidationResult.error("Cannot insert entity end '?>' into a processing instruction.");
+ }
+
+ if (target.length() >= 3 && target.substring(0, 3).equalsIgnoreCase("xml")) {
+ return ValidationResult.error("Processing instruction target must not start with 'xml'");
+ }
+
+ return ValidationResult.VALIDATE_OK;
+ }
+
+ /**
+ * Validate the data of an processing instruction.
+ *
+ * @param data
+ * The data String to validate.
+ * @return The IValidationResult. Use {@link IValidationResult#isOK()} to check if there is an error.
+ */
+ public static IValidationResult validateProcessingInstructionData(final String data) {
+ if (data.indexOf("?>") > -1) {
+ return ValidationResult.error("Cannot insert entity end '?>' into a processing instruction.");
+ }
+
+ return ValidationResult.VALIDATE_OK;
+ }
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java index bef5eb06..17ce850e 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/CopyVisitor.java @@ -1,12 +1,13 @@ /*******************************************************************************
- * Copyright (c) 2012 Florian Thienel and others.
+ * Copyright (c) 2012, 2013 Florian Thienel 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:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added processing instructions
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
@@ -15,6 +16,7 @@ import org.eclipse.vex.core.provisional.dom.IDocument; import org.eclipse.vex.core.provisional.dom.IDocumentFragment;
import org.eclipse.vex.core.provisional.dom.IElement;
import org.eclipse.vex.core.provisional.dom.INodeVisitorWithResult;
+import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
import org.eclipse.vex.core.provisional.dom.IText;
/**
@@ -48,4 +50,8 @@ public class CopyVisitor implements INodeVisitorWithResult<Node> { return new Comment();
}
+ public ProcessingInstruction visit(final IProcessingInstruction pi) {
+ return new ProcessingInstruction(pi.getTarget());
+ }
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java index b3fdf11e..9ad15f56 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DeepCopyVisitor.java @@ -1,3 +1,14 @@ +/*******************************************************************************
+ * Copyright (c) 2012, 2013 Florian Thienel 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:
+ * Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added processing instructions
+ *******************************************************************************/
package org.eclipse.vex.core.internal.dom;
import java.util.List;
@@ -11,6 +22,7 @@ import org.eclipse.vex.core.provisional.dom.IElement; import org.eclipse.vex.core.provisional.dom.INode;
import org.eclipse.vex.core.provisional.dom.INodeVisitor;
import org.eclipse.vex.core.provisional.dom.IParent;
+import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
import org.eclipse.vex.core.provisional.dom.IText;
/**
@@ -71,6 +83,12 @@ public class DeepCopyVisitor implements INodeVisitor { associate(comment, copy);
}
+ public void visit(final IProcessingInstruction pi) {
+ final ProcessingInstruction copy = (ProcessingInstruction) copy(pi);
+ addToParent(copy);
+ associate(pi, copy);
+ }
+
@SuppressWarnings("unchecked")
private <T extends INode> T copy(final T node) {
return (T) node.accept(copyVisitor);
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java index cacf6d46..f0a0e593 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java @@ -11,6 +11,7 @@ * Florian Thienel - refactoring to full fledged DOM * Carsten Hiesserich - bug fixes (bug 407801, 410659) * Carsten Hiesserich - added structuralChange flag to ContentChangeEvent + * Carsten Hiesserich - added support for processing instructions *******************************************************************************/ package org.eclipse.vex.core.internal.dom; @@ -24,6 +25,8 @@ import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.QualifiedName; +import org.eclipse.vex.core.IValidationResult; +import org.eclipse.vex.core.XML; import org.eclipse.vex.core.internal.core.ListenerList; import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult; import org.eclipse.vex.core.provisional.dom.ContentChangeEvent; @@ -41,6 +44,7 @@ import org.eclipse.vex.core.provisional.dom.INodeVisitor; import org.eclipse.vex.core.provisional.dom.INodeVisitorWithResult; import org.eclipse.vex.core.provisional.dom.IParent; import org.eclipse.vex.core.provisional.dom.IPosition; +import org.eclipse.vex.core.provisional.dom.IProcessingInstruction; import org.eclipse.vex.core.provisional.dom.IText; import org.eclipse.vex.core.provisional.dom.IValidator; @@ -229,6 +233,16 @@ public class Document extends Parent implements IDocument { } @Override + public Boolean visit(final IProcessingInstruction pi) { + for (final QualifiedName nodeName : nodeNames) { + if (!nodeName.equals(IValidator.PCDATA)) { + return false; + } + } + return true; + } + + @Override public Boolean visit(final IText text) { return true; } @@ -274,6 +288,22 @@ public class Document extends Parent implements IDocument { getContent().insertText(offset, adjustedText); fireContentInserted(new ContentChangeEvent(Document.this, comment.getParent(), new ContentRange(offset, offset + adjustedText.length() - 1), false)); } + + public void visit(final IProcessingInstruction pi) { + // The target is validated to ensure the instruction is valid after the insertion + final String charBefore = pi.getText(new ContentRange(offset - 1, offset - 1)); + final String charAfter = pi.getText(new ContentRange(offset, offset)); + final String candidate = charBefore + adjustedText + charAfter; + + final IValidationResult result = XML.validateProcessingInstructionTarget(candidate); + if (!result.isOK()) { + throw new DocumentValidationException(result.getMessage()); + } + + fireBeforeContentInserted(new ContentChangeEvent(Document.this, pi.getParent(), new ContentRange(offset, offset + adjustedText.length() - 1), false)); + getContent().insertText(offset, adjustedText); + fireContentInserted(new ContentChangeEvent(Document.this, pi.getParent(), new ContentRange(offset, offset + adjustedText.length() - 1), false)); + } }); } @@ -287,15 +317,38 @@ public class Document extends Parent implements IDocument { return new String(characters); } + /** + * Inserts a node at the given offset. There is no check that the insertion is valid. + * + * @param node + * The node to insert + * @param offset + * The content offset to insert the node at. + */ + private void insertNode(final Node node, final int offset) { + final Parent parent = getParentForInsertionAt(offset); + + fireBeforeContentInserted(new ContentChangeEvent(this, parent, new ContentRange(offset, offset + 1), true)); + + getContent().insertTagMarker(offset); + getContent().insertTagMarker(offset); + node.associate(getContent(), new ContentRange(offset, offset + 1)); + + parent.insertChildAt(offset, node); + + fireContentInserted(new ContentChangeEvent(this, parent, node.getRange(), true)); + } + + @Override public boolean canInsertComment(final int offset) { if (!(offset > getStartOffset() && offset <= getEndOffset())) { return false; } final INode node = getNodeForInsertionAt(offset); - if (node instanceof IComment) { - return false; + if (node instanceof IParent) { + return true; } - return true; + return false; } public IComment insertComment(final int offset) throws DocumentValidationException { @@ -303,20 +356,48 @@ public class Document extends Parent implements IDocument { throw new DocumentValidationException(MessageFormat.format("Cannot insert a comment at offset {0}.", offset)); } - final Parent parent = getParentForInsertionAt(offset); + final Comment comment = new Comment(); + insertNode(comment, offset); - fireBeforeContentInserted(new ContentChangeEvent(this, parent, new ContentRange(offset, offset + 1), true)); + return comment; + } - final Comment comment = new Comment(); - getContent().insertTagMarker(offset); - getContent().insertTagMarker(offset); - comment.associate(getContent(), new ContentRange(offset, offset + 1)); + @Override + public boolean canInsertProcessingInstruction(final int offset, final String target) { + if (!(offset > getStartOffset() && offset <= getEndOffset())) { + return false; + } + final INode node = getNodeForInsertionAt(offset); + if (!(node instanceof IParent)) { + // IComment and IProcessingInstructions are not derived from IParent + return false; + } + + if (target == null) { + // No validity check if target is null + return true; + } + + return XML.validateProcessingInstructionTarget(target).isOK(); + } - parent.insertChildAt(offset, comment); + @Override + public IProcessingInstruction insertProcessingInstruction(final int offset, final String target) throws DocumentValidationException { + // Validate first to throw an appropriate message + final IValidationResult resultTarget = XML.validateProcessingInstructionTarget(target); + if (!resultTarget.isOK()) { + throw new DocumentValidationException(resultTarget.getMessage()); + } - fireContentInserted(new ContentChangeEvent(this, parent, comment.getRange(), true)); + if (!canInsertProcessingInstruction(offset, target)) { + throw new DocumentValidationException(MessageFormat.format("Cannot insert a processing instruction at offset {0}.", offset)); + } - return comment; + // The constructor throws an Exception if the target is not valid. + final ProcessingInstruction pi = new ProcessingInstruction(target); + insertNode(pi, offset); + + return pi; } public boolean canInsertElement(final int offset, final QualifiedName elementName) { @@ -327,22 +408,13 @@ public class Document extends Parent implements IDocument { Assert.isTrue(offset > rootElement.getStartOffset() && offset <= rootElement.getEndOffset(), MessageFormat.format("Offset must be in [{0}, {1}]", rootElement.getStartOffset() + 1, rootElement.getEndOffset())); - final Element parent = getElementForInsertionAt(offset); final INode node = getNodeForInsertionAt(offset); if (!canInsertAt(node, offset, elementName)) { throw new DocumentValidationException(MessageFormat.format("Cannot insert element {0} at offset {1}.", elementName, offset)); } - fireBeforeContentInserted(new ContentChangeEvent(this, parent, new ContentRange(offset, offset + 1), true)); - final Element element = new Element(elementName); - getContent().insertTagMarker(offset); - getContent().insertTagMarker(offset); - element.associate(getContent(), new ContentRange(offset, offset + 1)); - - parent.insertChildAt(offset, element); - - fireContentInserted(new ContentChangeEvent(this, parent, element.getRange(), true)); + insertNode(element, offset); return element; } diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/FindUndeclaredNamespacesVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/FindUndeclaredNamespacesVisitor.java index babdbe32..2062e18a 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/FindUndeclaredNamespacesVisitor.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/FindUndeclaredNamespacesVisitor.java @@ -4,9 +4,10 @@ * 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:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added processing instruction
*******************************************************************************/
package org.eclipse.vex.core.internal.dom;
@@ -21,6 +22,7 @@ import org.eclipse.vex.core.provisional.dom.IDocumentFragment; import org.eclipse.vex.core.provisional.dom.IElement;
import org.eclipse.vex.core.provisional.dom.INode;
import org.eclipse.vex.core.provisional.dom.INodeVisitorWithResult;
+import org.eclipse.vex.core.provisional.dom.IProcessingInstruction;
import org.eclipse.vex.core.provisional.dom.IText;
/**
@@ -67,6 +69,10 @@ public class FindUndeclaredNamespacesVisitor implements INodeVisitorWithResult<S return Collections.emptySet();
}
+ public Set<String> visit(final IProcessingInstruction pi) {
+ return Collections.emptySet();
+ }
+
private Set<String> visitAll(final Iterable<INode> iterable) {
final Set<String> result = new HashSet<String>();
for (final INode node : iterable) {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ProcessingInstruction.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ProcessingInstruction.java new file mode 100644 index 00000000..336cd2ef --- /dev/null +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/ProcessingInstruction.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2013 Carsten Hiesserich 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: + * Carsten Hiesserich - initial API and implementation + *******************************************************************************/ +package org.eclipse.vex.core.internal.dom; + +import org.eclipse.vex.core.IValidationResult; +import org.eclipse.vex.core.XML; +import org.eclipse.vex.core.provisional.dom.DocumentValidationException; +import org.eclipse.vex.core.provisional.dom.INode; +import org.eclipse.vex.core.provisional.dom.INodeVisitor; +import org.eclipse.vex.core.provisional.dom.INodeVisitorWithResult; +import org.eclipse.vex.core.provisional.dom.IProcessingInstruction; + +/** + * A representation of an XML processing insctruction in the DOM. PI's have textual content, a start and an end tag. + * + * @author Carsten Hiesserich + */ +public class ProcessingInstruction extends Node implements IProcessingInstruction { + + private String target = null; + + /** + * Create a new processing instruction. + * + * @param target + * The target for this processing instruction. + * @throws DocumentValidationException + * If the given String is no valid target. + */ + public ProcessingInstruction(final String target) throws DocumentValidationException { + setTarget(target); + } + + @Override + public void accept(final INodeVisitor visitor) { + visitor.visit(this); + } + + @Override + public <T> T accept(final INodeVisitorWithResult<T> visitor) { + return visitor.visit(this); + } + + @Override + public boolean isKindOf(final INode node) { + if (!(node instanceof IProcessingInstruction)) { + return false; + } + return true; + } + + @Override + public String getTarget() { + return target; + } + + @Override + public void setTarget(final String target) throws DocumentValidationException { + final IValidationResult resultTarget = XML.validateProcessingInstructionTarget(target); + if (!resultTarget.isOK()) { + throw new DocumentValidationException(resultTarget.getMessage()); + } + + this.target = target; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer(); + + sb.append("ProcessingInstruction ("); + if (target != null) { + sb.append(target); + sb.append(") ("); + } + if (isAssociated()) { + sb.append(getStartOffset()); + sb.append(","); + sb.append(getEndOffset()); + } else { + sb.append("n/a"); + } + sb.append(")"); + + return sb.toString(); + } + +} diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java index 24a06d80..12fbe5a1 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentBuilder.java @@ -4,11 +4,12 @@ * 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: * John Krasnay - initial API and implementation * Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325) * Carsten Hiesserich - do not add text nodes containing only whitespace when reading the document (bug 407803) + * Carsten Hiesserich - added processing instructions support *******************************************************************************/ package org.eclipse.vex.core.internal.io; @@ -29,6 +30,7 @@ import org.eclipse.vex.core.internal.dom.Document; import org.eclipse.vex.core.internal.dom.Element; import org.eclipse.vex.core.internal.dom.GapContent; import org.eclipse.vex.core.internal.dom.Node; +import org.eclipse.vex.core.internal.dom.ProcessingInstruction; import org.eclipse.vex.core.provisional.dom.BaseNodeVisitorWithResult; import org.eclipse.vex.core.provisional.dom.ContentRange; import org.eclipse.vex.core.provisional.dom.DocumentContentModel; @@ -176,6 +178,26 @@ public class DocumentBuilder implements ContentHandler, LexicalHandler { } public void processingInstruction(final String target, final String data) { + + final ProcessingInstruction pi = new ProcessingInstruction(target); + + if (isBeforeRoot()) { + nodesBeforeRoot.add(pi); + } else if (isAfterRoot()) { + nodesAfterRoot.add(pi); + } else { + final Element parent = stack.getLast().element; + parent.addChild(pi); + appendChars(false); + } + + final int startOffset = content.length(); + content.insertTagMarker(content.length()); + content.insertText(content.length(), data); + content.insertTagMarker(content.length()); + pi.associate(content, new ContentRange(startOffset, content.length() - 1)); + + trimLeading = false; // Keep a leading whitespace after a processing instruction } public void setDocumentLocator(final Locator locator) { diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java index 5dd9ab43..6592b337 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/io/DocumentWriter.java @@ -4,11 +4,12 @@ * 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: * John Krasnay - initial API and implementation * Igor Jacy Lino Campista - Java 5 warnings fixed (bug 311325) * Carsten Hiesserich - writeNoWrap(DocumentFragment) method + * Carsten Hiesserich - added processing instructions support *******************************************************************************/ package org.eclipse.vex.core.internal.io; @@ -27,6 +28,7 @@ import org.eclipse.vex.core.provisional.dom.IDocument; import org.eclipse.vex.core.provisional.dom.IDocumentFragment; import org.eclipse.vex.core.provisional.dom.IElement; import org.eclipse.vex.core.provisional.dom.INode; +import org.eclipse.vex.core.provisional.dom.IProcessingInstruction; import org.eclipse.vex.core.provisional.dom.IText; import org.eclipse.vex.core.provisional.dom.IValidator; @@ -282,6 +284,15 @@ public class DocumentWriter { } @Override + public void visit(final IProcessingInstruction pi) { + // Text in PI's is written as is with no wrapping + out.print(indent); + out.print("<?"); + out.print(pi.getTarget() + " " + node.getText()); + out.println("?>"); + } + + @Override public void visit(final IText text) { final TextWrapper wrapper = new TextWrapper(); wrapper.add(escape(node.getText())); @@ -323,6 +334,13 @@ public class DocumentWriter { } @Override + public void visit(final IProcessingInstruction pi) { + out.print("<?"); + out.print(pi.getTarget() + " " + node.getText()); + out.print("?>"); + } + + @Override public void visit(final IText text) { out.print(escape(node.getText())); } @@ -376,6 +394,13 @@ public class DocumentWriter { } @Override + public void visit(final IProcessingInstruction pi) { + wrapper.addNoSplit("<?"); + wrapper.add(pi.getTarget() + " " + node.getText()); + wrapper.addNoSplit("?>"); + } + + @Override public void visit(final IText text) { wrapper.add(escape(node.getText())); } diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitor.java index 28a9a12c..0f952aee 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitor.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitor.java @@ -4,9 +4,10 @@ * 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:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added processing instruction
*******************************************************************************/
package org.eclipse.vex.core.provisional.dom;
@@ -37,4 +38,8 @@ public class BaseNodeVisitor implements INodeVisitor { public void visit(final IComment comment) {
// ignore
}
+
+ public void visit(final IProcessingInstruction pi) {
+ // ignore
+ }
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitorWithResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitorWithResult.java index f1943576..dafac01b 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitorWithResult.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/BaseNodeVisitorWithResult.java @@ -4,9 +4,10 @@ * 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:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added processing instruction
*******************************************************************************/
package org.eclipse.vex.core.provisional.dom;
@@ -49,4 +50,8 @@ public class BaseNodeVisitorWithResult<T> implements INodeVisitorWithResult<T> { public T visit(final IComment comment) {
return defaultValue;
}
+
+ public T visit(final IProcessingInstruction pi) {
+ return defaultValue;
+ }
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java index a09c8d52..cf54eb93 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IDocument.java @@ -151,6 +151,27 @@ public interface IDocument extends IParent { boolean canInsertComment(int offset);
/**
+ * Insert a new procesing instruction at the given offset.
+ *
+ * @see IProcessingInstruction
+ * @param offset
+ * the offset at which the processing instruction should be inserted
+ * @return the new processing instruction
+ * @throws DocumentValidationException
+ * if a processing instruction is not allowed at the given offset (e.g. within an existing processing
+ * instr.)
+ */
+ IProcessingInstruction insertProcessingInstruction(int offset, String target) throws DocumentValidationException;
+
+ /**
+ * @param offset
+ * @param target
+ * The target of the pi to insert. If null, validity of target is not checked.
+ * @return true if a processing instruction can be inserted a the given offset
+ */
+ boolean canInsertProcessingInstruction(int offset, String target);
+
+ /**
* Insert a new comment at the given offset.
*
* @see IComment
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitor.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitor.java index de1aad6d..506e70c6 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitor.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitor.java @@ -1,12 +1,13 @@ /*******************************************************************************
- * Copyright (c) 2012 Florian Thienel and others.
+ * Copyright (c) 2013 Florian Thienel 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:
* Florian Thienel - initial API and implementation
+ * Carsten Hiesserich - added processing instruction
*******************************************************************************/
package org.eclipse.vex.core.provisional.dom;
@@ -28,4 +29,6 @@ public interface INodeVisitor { void visit(IComment comment);
+ void visit(IProcessingInstruction pi);
+
}
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitorWithResult.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitorWithResult.java index 035957d8..580e4f75 100644 --- a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitorWithResult.java +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/INodeVisitorWithResult.java @@ -1,31 +1,33 @@ -/*******************************************************************************
- * Copyright (c) 2012 Florian Thienel 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:
- * Florian Thienel - initial API and implementation
- *******************************************************************************/
-package org.eclipse.vex.core.provisional.dom;
-
-/**
- * An incarantion of the <a href="http://en.wikipedia.org/wiki/Visitor_pattern">Visitor pattern</a> which handles the
- * nodes of the structural part of the DOM and is able to return a value of a certain type.
- *
- * @author Florian Thienel
- */
-public interface INodeVisitorWithResult<T> {
-
- T visit(IDocument document);
-
- T visit(IDocumentFragment fragment);
-
- T visit(IElement element);
-
- T visit(IText text);
-
- T visit(IComment comment);
-
-}
+/******************************************************************************* + * Copyright (c) 2013 Florian Thienel 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: + * Florian Thienel - initial API and implementation + * Carsten Hieserich - added processing instruction + *******************************************************************************/ +package org.eclipse.vex.core.provisional.dom; + +/** + * An incarantion of the <a href="http://en.wikipedia.org/wiki/Visitor_pattern">Visitor pattern</a> which handles the + * nodes of the structural part of the DOM and is able to return a value of a certain type. + * + * @author Florian Thienel + */ +public interface INodeVisitorWithResult<T> { + + T visit(IDocument document); + + T visit(IDocumentFragment fragment); + + T visit(IElement element); + + T visit(IText text); + + T visit(IComment comment); + + T visit(IProcessingInstruction pi); +} diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IProcessingInstruction.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IProcessingInstruction.java new file mode 100644 index 00000000..f6e3e946 --- /dev/null +++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/provisional/dom/IProcessingInstruction.java @@ -0,0 +1,34 @@ +/*******************************************************************************
+ * Copyright (c) 2013 Carsten Hiesserich 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:
+ * Carsten Hiesserich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.vex.core.provisional.dom;
+
+/**
+ * A representation of an XML processing insctruction in the DOM. PI's have textual content, a start and an end tag.
+ *
+ * @author Carsten Hiesserich
+ */
+public interface IProcessingInstruction extends INode {
+
+ /**
+ * @return the target of this processing instruction .
+ */
+ public String getTarget();
+
+ /**
+ * Set the target of this processing instruction.
+ *
+ * @param target
+ * The new target.
+ * @throws DocumentValidationException
+ * If the given String is no valid target.
+ */
+ public void setTarget(String target) throws DocumentValidationException;
+}
\ No newline at end of file |