diff --git a/release-notes/VERSION b/release-notes/VERSION index 10bcd42d..27008b36 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -10,6 +10,9 @@ Project: woodstox 5.3.1 (not yet released) +#104: `NullPointerException` in `DTDValidator.validateElementEnd()` + for element undefined in DTD + (reported by ChrisTrenkamp@github) #105: W3CSchemaFactory constructor incorrectly references relaxng 5.3.0 (15-Jul-2019) diff --git a/src/main/java/com/ctc/wstx/dtd/DTDValidator.java b/src/main/java/com/ctc/wstx/dtd/DTDValidator.java index d750320c..18862913 100644 --- a/src/main/java/com/ctc/wstx/dtd/DTDValidator.java +++ b/src/main/java/com/ctc/wstx/dtd/DTDValidator.java @@ -331,10 +331,10 @@ public int validateElementEnd(String localName, String uri, String prefix) throws XMLStreamException { // First, let's remove the top: - int ix = mElemCount-1; - /* [WSTX-200]: need to avoid problems when doing sub-tree - * validation... - */ + final int ix = mElemCount-1; + + // [WSTX-200]: need to avoid problems when doing sub-tree + // validation... if (ix < 0) { return XMLValidator.CONTENT_ALLOW_WS; } @@ -359,7 +359,13 @@ public int validateElementEnd(String localName, String uri, String prefix) // doesn't really matter; epilog/prolog differently handled: return XMLValidator.CONTENT_ALLOW_WS; } - return mElems[ix-1].getAllowedContent(); + + final DTDElement element = mElems[ix-1]; + + // 22-Apr-2020, tatu: `null` validator added for unknown elements + return (element == null) + ? XMLValidator.CONTENT_ALLOW_ANY_TEXT + : element.getAllowedContent(); } //public void validateText(String text, boolean lastTextSegment) ; diff --git a/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java b/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java new file mode 100644 index 00000000..739f42bf --- /dev/null +++ b/src/test/java/wstxtest/vstream/TestDTDErrorCollection104Test.java @@ -0,0 +1,103 @@ +package wstxtest.vstream; + +import stax2.BaseStax2Test; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.stream.*; + +import org.codehaus.stax2.XMLStreamReader2; +import org.codehaus.stax2.validation.ValidationProblemHandler; +import org.codehaus.stax2.validation.XMLValidationException; +import org.codehaus.stax2.validation.XMLValidationProblem; +import org.codehaus.stax2.validation.XMLValidationSchema; +import org.codehaus.stax2.validation.XMLValidationSchemaFactory; + +public class TestDTDErrorCollection104Test + extends BaseStax2Test +{ + // [woodstox-core#103] + public void testValidationBeyondUnknownElement() throws Exception + { + final String DOC = + "\n" + + " \n" + + " \n" + + " \n" + + "\n"; + + final String INPUT_DTD = +"\n" ++"\n" +; + + XMLInputFactory f = getInputFactory(); + setCoalescing(f, true); + + XMLValidationSchemaFactory schemaFactory = + XMLValidationSchemaFactory.newInstance(XMLValidationSchema.SCHEMA_ID_DTD); + XMLValidationSchema schema = schemaFactory.createSchema(new StringReader(INPUT_DTD)); + XMLStreamReader2 sr = (XMLStreamReader2)f.createXMLStreamReader( + new StringReader(DOC)); + + final List probs = new ArrayList(); + + sr.validateAgainst(schema); + sr.setValidationProblemHandler(new ValidationProblemHandler() { + @Override + public void reportProblem(XMLValidationProblem problem) + throws XMLValidationException { + probs.add(problem); + } + }); + + assertTokenType(START_ELEMENT, sr.next()); + assertEquals("map", sr.getLocalName()); + + sr.next(); // SPACE or CHARACTERS + assertTokenType(START_ELEMENT, sr.next()); + assertEquals("val", sr.getLocalName()); + assertEquals(1, probs.size()); + assertEquals("Undefined element encountered", + probs.get(0).getMessage()); + + sr.next(); // SPACE or CHARACTERS + assertEquals(1, probs.size()); + + // From this point on, however, behavior bit unclear except + // that for DTD I guess we can at least check for undefined + // cases.... + + assertTokenType(START_ELEMENT, sr.next()); + assertEquals("prop", sr.getLocalName()); + // not defined either so: + assertEquals(2, probs.size()); + assertEquals("Undefined element encountered", + probs.get(1).getMessage()); + + assertTokenType(END_ELEMENT, sr.next()); + assertEquals("prop", sr.getLocalName()); + assertEquals(2, probs.size()); + + sr.next(); // SPACE or CHARACTERS + assertEquals(2, probs.size()); + assertTokenType(END_ELEMENT, sr.next()); + assertEquals("val", sr.getLocalName()); + assertEquals(2, probs.size()); + + sr.next(); // SPACE or CHARACTERS + assertTokenType(END_ELEMENT, sr.next()); + assertEquals("map", sr.getLocalName()); + assertEquals(3, probs.size()); + assertEquals("Validation error, element : Expected at least one element ", + probs.get(2).getMessage()); + + // Plus content model now missing (s) + assertTokenType(END_DOCUMENT, sr.next()); + assertEquals(3, probs.size()); + + sr.close(); + } +}