Skip to content

Commit

Permalink
WstxValidationException: Unknown reason (at end element
Browse files Browse the repository at this point in the history
</nl:nillableIntElement>) when validating a document with nillable
elements fix FasterXML#179 fix FasterXML#190
  • Loading branch information
ppalaga committed Jan 14, 2024
1 parent e9d41a2 commit 47b32c7
Show file tree
Hide file tree
Showing 19 changed files with 910 additions and 553 deletions.
206 changes: 151 additions & 55 deletions src/main/java/com/ctc/wstx/sw/BaseNsStreamWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
import javax.xml.stream.events.StartElement;

import org.codehaus.stax2.ri.typed.AsciiValueEncoder;
import org.codehaus.stax2.validation.XMLValidationException;
import org.codehaus.stax2.validation.XMLValidationSchema;
import org.codehaus.stax2.validation.XMLValidator;

import com.ctc.wstx.api.EmptyElementHandler;
import com.ctc.wstx.api.WriterConfig;
import com.ctc.wstx.api.WstxInputProperties;
import com.ctc.wstx.cfg.ErrorConsts;
import com.ctc.wstx.cfg.XmlConsts;
import com.ctc.wstx.exc.WstxIOException;
import com.ctc.wstx.util.DefaultXmlSymbolTable;

Expand Down Expand Up @@ -246,9 +249,6 @@ public void writeEmptyElement(String localName)
throws XMLStreamException
{
checkStartElement(localName, null);
if (mValidator != null) {
mValidator.validateElementStart(localName, XmlConsts.ELEM_NO_NS_URI, XmlConsts.ELEM_NO_PREFIX);
}
mEmptyElement = true;
if (mOutputElemPool != null) {
SimpleOutputElement newCurr = mOutputElemPool;
Expand Down Expand Up @@ -294,9 +294,6 @@ public void writeStartElement(String localName)
throws XMLStreamException
{
checkStartElement(localName, null);
if (mValidator != null) {
mValidator.validateElementStart(localName, XmlConsts.ELEM_NO_NS_URI, XmlConsts.ELEM_NO_PREFIX);
}
mEmptyElement = false;
if (mOutputElemPool != null) {
SimpleOutputElement newCurr = mOutputElemPool;
Expand Down Expand Up @@ -334,19 +331,19 @@ protected void writeTypedAttribute(String prefix, String nsURI, String localName
if (!mStartElementOpen) {
throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM);
}
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
mCurrElem.checkAttrWrite(nsURI, localName);
}
try {
if (mValidator == null) {
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
mCurrElem.addAttribute(nsURI, localName, null, null);
}
if (prefix == null || prefix.length() == 0) {
mWriter.writeTypedAttribute(localName, enc);
} else {
mWriter.writeTypedAttribute(prefix, localName, enc);
}
} else {
mWriter.writeTypedAttribute
(prefix, localName, nsURI, enc, mValidator, getCopyBuffer());
(prefix, localName, nsURI, enc, mCurrElem.getAttributeCollector(), getCopyBuffer());
}
} catch (IOException ioe) {
throw new WstxIOException(ioe);
Expand Down Expand Up @@ -430,7 +427,16 @@ protected void closeStartElement(boolean emptyElem)
}

if (mValidator != null) {
mVldContent = mValidator.validateElementAndAttributes();
try {
mVldContent = mCurrElem.validateElementStartAndAttributes();
if (emptyElem) {
mVldContent = mValidator.validateElementEnd
(mCurrElem.getLocalName(), mCurrElem.getNamespaceURI(), mCurrElem.getPrefix());
}
} catch (XMLValidationException e) {
mVldException = e;
throw e;
}
}

// Need bit more special handling for empty elements...
Expand All @@ -440,10 +446,6 @@ protected void closeStartElement(boolean emptyElem)
if (mCurrElem.isRoot()) { // Did we close the root? (isRoot() returns true for the virtual "document node")
mState = STATE_EPILOG;
}
if (mValidator != null) {
mVldContent = mValidator.validateElementEnd
(curr.getLocalName(), curr.getNamespaceURI(), curr.getPrefix());
}
if (mPoolSize < MAX_POOL_SIZE) {
curr.addToPool(mOutputElemPool);
mOutputElemPool = curr;
Expand Down Expand Up @@ -471,6 +473,9 @@ protected String getTopElementDesc() {
protected void checkStartElement(String localName, String prefix)
throws XMLStreamException
{
if (mVldException != null) {
throw new XMLStreamException("Cannot start an element after a validation error", mVldException);
}
// Need to finish an open start element?
if (mStartElementOpen) {
closeStartElement(mEmptyElement);
Expand All @@ -493,13 +498,14 @@ protected final void doWriteAttr(String localName, String nsURI, String prefix,
String value)
throws XMLStreamException
{
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
mCurrElem.checkAttrWrite(nsURI, localName);
}
if (mValidator != null) {
// No need to get it normalized... even if validator does normalize
// it, we don't use that for anything
mValidator.validateAttribute(localName, nsURI, prefix, value);
if (mCheckAttrs) {
// ensure no duplicate attrs and possibly pass them to validator when closing the start element
try {
mCurrElem.addAttribute(nsURI, localName, prefix, value);
} catch (XMLValidationException e) {
mVldException = e;
throw e;
}
}
try {
int vlen = value.length();
Expand Down Expand Up @@ -532,29 +538,6 @@ protected final void doWriteAttr(String localName, String nsURI, String prefix,
}
}

protected final void doWriteAttr(String localName, String nsURI, String prefix,
char[] buf, int start, int len)
throws XMLStreamException
{
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
mCurrElem.checkAttrWrite(nsURI, localName);
}
if (mValidator != null) {
// No need to get it normalized... even if validator does normalize
// it, we don't use that for anything
mValidator.validateAttribute(localName, nsURI, prefix, buf, start, len);
}
try {
if (prefix != null && prefix.length() > 0) {
mWriter.writeAttribute(prefix, localName, buf, start, len);
} else {
mWriter.writeAttribute(localName, buf, start, len);
}
} catch (IOException ioe) {
throw new WstxIOException(ioe);
}
}

protected void doWriteNamespace(String prefix, String nsURI)
throws XMLStreamException
{
Expand Down Expand Up @@ -653,11 +636,28 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
}

// Better have something to close... (to figure out what to close)
if (mState != STATE_TREE) {
if (mVldException != null) {
throw new XMLStreamException("Cannot start an element after a validation error", mVldException);
} else if (mState != STATE_TREE) {
// Have to always throw exception... don't necessarily know the name
reportNwfStructure("No open start element, when trying to write end element");
}

if (mStartElementOpen) {
if (mValidator != null) {
// We need to validate here, before we move the mCurrElem
try {
/* Note: return value is not of much use, since the
* element will be closed right away...
*/
mVldContent = mCurrElem.validateElementStartAndAttributes();
} catch (XMLValidationException e) {
mVldException = e;
throw e;
}
}
}

SimpleOutputElement thisElem = mCurrElem;
String prefix = thisElem.getPrefix();
String localName = thisElem.getLocalName();
Expand Down Expand Up @@ -691,12 +691,6 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
/* Can't/shouldn't call closeStartElement, but need to do same
* processing. Thus, this is almost identical to closeStartElement:
*/
if (mValidator != null) {
/* Note: return value is not of much use, since the
* element will be closed right away...
*/
mVldContent = mValidator.validateElementAndAttributes();
}
mStartElementOpen = false;
try {
//If an EmptyElementHandler is provided use it to determine if allowEmpty is set
Expand All @@ -710,7 +704,12 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
mState = STATE_EPILOG;
}
if (mValidator != null) {
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
try {
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
} catch (XMLValidationException e) {
mVldException = e;
throw e;
}
}
return;
}
Expand All @@ -733,7 +732,12 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)

// Ok, time to validate...
if (mValidator != null) {
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
try {
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
} catch (XMLValidationException e) {
mVldException = e;
throw e;
}
}
}

Expand Down Expand Up @@ -763,4 +767,96 @@ protected abstract void writeStartOrEmpty(String localName, String nsURI)

protected abstract void writeStartOrEmpty(String prefix, String localName, String nsURI)
throws XMLStreamException;

/*
///////////////////////////////////////////////////////////////////////
// Attribute access
///////////////////////////////////////////////////////////////////////
*/

@Override
public int getAttributeCount()
{
return mCurrElem.getAttributeCount();
}

@Override
public String getAttributeLocalName(int index)
{
return mCurrElem.getAttributeLocalName(index);
}

@Override
public String getAttributeNamespace(int index)
{
return mCurrElem.getAttributeNamespace(index);
}

@Override
public String getAttributePrefix(int index)
{
return mCurrElem.getAttributePrefix(index);
}

@Override
public String getAttributeValue(int index)
{
return mCurrElem.getAttributeValue(index);
}

@Override
public String getAttributeValue(String nsURI, String localName)
{
return mCurrElem.getAttributeValue(nsURI, localName);
}

@Override
public String getAttributeType(int index) {
return (mValidator == null) ? WstxInputProperties.UNKNOWN_ATTR_TYPE :
mValidator.getAttributeType(index);
}

@Override
public int findAttributeIndex(String nsURI, String localName)
{
return mCurrElem.findAttributeIndex(nsURI, localName);
}

/*
///////////////////////////////////////////////////////////////////////
// Overrides to keep the validator up to date in SimpleOutputElement instances
///////////////////////////////////////////////////////////////////////
*/

@Override
public XMLValidator validateAgainst(XMLValidationSchema schema) throws XMLStreamException {
final XMLValidator validateAgainst = super.validateAgainst(schema);
mCurrElem.setValidator(mValidator);
if (mOutputElemPool != null) {
mOutputElemPool.setValidator(mValidator);
}
return validateAgainst;
}

@Override
public XMLValidator stopValidatingAgainst(XMLValidationSchema schema) throws XMLStreamException {
final XMLValidator result = super.stopValidatingAgainst(schema);
mCurrElem.setValidator(mValidator);
if (mOutputElemPool != null) {
mOutputElemPool.setValidator(mValidator);
}
return result;
}

@Override
public XMLValidator stopValidatingAgainst(XMLValidator validator) throws XMLStreamException {
final XMLValidator result = super.stopValidatingAgainst(validator);
mCurrElem.setValidator(mValidator);
if (mOutputElemPool != null) {
mOutputElemPool.setValidator(mValidator);
}
return result;
}


}
Loading

0 comments on commit 47b32c7

Please sign in to comment.