Skip to content

Commit 47b32c7

Browse files
committed
WstxValidationException: Unknown reason (at end element
</nl:nillableIntElement>) when validating a document with nillable elements fix FasterXML#179 fix FasterXML#190
1 parent e9d41a2 commit 47b32c7

19 files changed

+910
-553
lines changed

src/main/java/com/ctc/wstx/sw/BaseNsStreamWriter.java

Lines changed: 151 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@
2424
import javax.xml.stream.events.StartElement;
2525

2626
import org.codehaus.stax2.ri.typed.AsciiValueEncoder;
27+
import org.codehaus.stax2.validation.XMLValidationException;
28+
import org.codehaus.stax2.validation.XMLValidationSchema;
29+
import org.codehaus.stax2.validation.XMLValidator;
2730

2831
import com.ctc.wstx.api.EmptyElementHandler;
2932
import com.ctc.wstx.api.WriterConfig;
33+
import com.ctc.wstx.api.WstxInputProperties;
3034
import com.ctc.wstx.cfg.ErrorConsts;
31-
import com.ctc.wstx.cfg.XmlConsts;
3235
import com.ctc.wstx.exc.WstxIOException;
3336
import com.ctc.wstx.util.DefaultXmlSymbolTable;
3437

@@ -246,9 +249,6 @@ public void writeEmptyElement(String localName)
246249
throws XMLStreamException
247250
{
248251
checkStartElement(localName, null);
249-
if (mValidator != null) {
250-
mValidator.validateElementStart(localName, XmlConsts.ELEM_NO_NS_URI, XmlConsts.ELEM_NO_PREFIX);
251-
}
252252
mEmptyElement = true;
253253
if (mOutputElemPool != null) {
254254
SimpleOutputElement newCurr = mOutputElemPool;
@@ -294,9 +294,6 @@ public void writeStartElement(String localName)
294294
throws XMLStreamException
295295
{
296296
checkStartElement(localName, null);
297-
if (mValidator != null) {
298-
mValidator.validateElementStart(localName, XmlConsts.ELEM_NO_NS_URI, XmlConsts.ELEM_NO_PREFIX);
299-
}
300297
mEmptyElement = false;
301298
if (mOutputElemPool != null) {
302299
SimpleOutputElement newCurr = mOutputElemPool;
@@ -334,19 +331,19 @@ protected void writeTypedAttribute(String prefix, String nsURI, String localName
334331
if (!mStartElementOpen) {
335332
throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM);
336333
}
337-
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
338-
mCurrElem.checkAttrWrite(nsURI, localName);
339-
}
340334
try {
341335
if (mValidator == null) {
336+
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
337+
mCurrElem.addAttribute(nsURI, localName, null, null);
338+
}
342339
if (prefix == null || prefix.length() == 0) {
343340
mWriter.writeTypedAttribute(localName, enc);
344341
} else {
345342
mWriter.writeTypedAttribute(prefix, localName, enc);
346343
}
347344
} else {
348345
mWriter.writeTypedAttribute
349-
(prefix, localName, nsURI, enc, mValidator, getCopyBuffer());
346+
(prefix, localName, nsURI, enc, mCurrElem.getAttributeCollector(), getCopyBuffer());
350347
}
351348
} catch (IOException ioe) {
352349
throw new WstxIOException(ioe);
@@ -430,7 +427,16 @@ protected void closeStartElement(boolean emptyElem)
430427
}
431428

432429
if (mValidator != null) {
433-
mVldContent = mValidator.validateElementAndAttributes();
430+
try {
431+
mVldContent = mCurrElem.validateElementStartAndAttributes();
432+
if (emptyElem) {
433+
mVldContent = mValidator.validateElementEnd
434+
(mCurrElem.getLocalName(), mCurrElem.getNamespaceURI(), mCurrElem.getPrefix());
435+
}
436+
} catch (XMLValidationException e) {
437+
mVldException = e;
438+
throw e;
439+
}
434440
}
435441

436442
// Need bit more special handling for empty elements...
@@ -440,10 +446,6 @@ protected void closeStartElement(boolean emptyElem)
440446
if (mCurrElem.isRoot()) { // Did we close the root? (isRoot() returns true for the virtual "document node")
441447
mState = STATE_EPILOG;
442448
}
443-
if (mValidator != null) {
444-
mVldContent = mValidator.validateElementEnd
445-
(curr.getLocalName(), curr.getNamespaceURI(), curr.getPrefix());
446-
}
447449
if (mPoolSize < MAX_POOL_SIZE) {
448450
curr.addToPool(mOutputElemPool);
449451
mOutputElemPool = curr;
@@ -471,6 +473,9 @@ protected String getTopElementDesc() {
471473
protected void checkStartElement(String localName, String prefix)
472474
throws XMLStreamException
473475
{
476+
if (mVldException != null) {
477+
throw new XMLStreamException("Cannot start an element after a validation error", mVldException);
478+
}
474479
// Need to finish an open start element?
475480
if (mStartElementOpen) {
476481
closeStartElement(mEmptyElement);
@@ -493,13 +498,14 @@ protected final void doWriteAttr(String localName, String nsURI, String prefix,
493498
String value)
494499
throws XMLStreamException
495500
{
496-
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
497-
mCurrElem.checkAttrWrite(nsURI, localName);
498-
}
499-
if (mValidator != null) {
500-
// No need to get it normalized... even if validator does normalize
501-
// it, we don't use that for anything
502-
mValidator.validateAttribute(localName, nsURI, prefix, value);
501+
if (mCheckAttrs) {
502+
// ensure no duplicate attrs and possibly pass them to validator when closing the start element
503+
try {
504+
mCurrElem.addAttribute(nsURI, localName, prefix, value);
505+
} catch (XMLValidationException e) {
506+
mVldException = e;
507+
throw e;
508+
}
503509
}
504510
try {
505511
int vlen = value.length();
@@ -532,29 +538,6 @@ protected final void doWriteAttr(String localName, String nsURI, String prefix,
532538
}
533539
}
534540

535-
protected final void doWriteAttr(String localName, String nsURI, String prefix,
536-
char[] buf, int start, int len)
537-
throws XMLStreamException
538-
{
539-
if (mCheckAttrs) { // still need to ensure no duplicate attrs?
540-
mCurrElem.checkAttrWrite(nsURI, localName);
541-
}
542-
if (mValidator != null) {
543-
// No need to get it normalized... even if validator does normalize
544-
// it, we don't use that for anything
545-
mValidator.validateAttribute(localName, nsURI, prefix, buf, start, len);
546-
}
547-
try {
548-
if (prefix != null && prefix.length() > 0) {
549-
mWriter.writeAttribute(prefix, localName, buf, start, len);
550-
} else {
551-
mWriter.writeAttribute(localName, buf, start, len);
552-
}
553-
} catch (IOException ioe) {
554-
throw new WstxIOException(ioe);
555-
}
556-
}
557-
558541
protected void doWriteNamespace(String prefix, String nsURI)
559542
throws XMLStreamException
560543
{
@@ -653,11 +636,28 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
653636
}
654637

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

646+
if (mStartElementOpen) {
647+
if (mValidator != null) {
648+
// We need to validate here, before we move the mCurrElem
649+
try {
650+
/* Note: return value is not of much use, since the
651+
* element will be closed right away...
652+
*/
653+
mVldContent = mCurrElem.validateElementStartAndAttributes();
654+
} catch (XMLValidationException e) {
655+
mVldException = e;
656+
throw e;
657+
}
658+
}
659+
}
660+
661661
SimpleOutputElement thisElem = mCurrElem;
662662
String prefix = thisElem.getPrefix();
663663
String localName = thisElem.getLocalName();
@@ -691,12 +691,6 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
691691
/* Can't/shouldn't call closeStartElement, but need to do same
692692
* processing. Thus, this is almost identical to closeStartElement:
693693
*/
694-
if (mValidator != null) {
695-
/* Note: return value is not of much use, since the
696-
* element will be closed right away...
697-
*/
698-
mVldContent = mValidator.validateElementAndAttributes();
699-
}
700694
mStartElementOpen = false;
701695
try {
702696
//If an EmptyElementHandler is provided use it to determine if allowEmpty is set
@@ -710,7 +704,12 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
710704
mState = STATE_EPILOG;
711705
}
712706
if (mValidator != null) {
713-
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
707+
try {
708+
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
709+
} catch (XMLValidationException e) {
710+
mVldException = e;
711+
throw e;
712+
}
714713
}
715714
return;
716715
}
@@ -733,7 +732,12 @@ protected void doWriteEndTag(QName expName, boolean allowEmpty)
733732

734733
// Ok, time to validate...
735734
if (mValidator != null) {
736-
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
735+
try {
736+
mVldContent = mValidator.validateElementEnd(localName, nsURI, prefix);
737+
} catch (XMLValidationException e) {
738+
mVldException = e;
739+
throw e;
740+
}
737741
}
738742
}
739743

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

764768
protected abstract void writeStartOrEmpty(String prefix, String localName, String nsURI)
765769
throws XMLStreamException;
770+
771+
/*
772+
///////////////////////////////////////////////////////////////////////
773+
// Attribute access
774+
///////////////////////////////////////////////////////////////////////
775+
*/
776+
777+
@Override
778+
public int getAttributeCount()
779+
{
780+
return mCurrElem.getAttributeCount();
781+
}
782+
783+
@Override
784+
public String getAttributeLocalName(int index)
785+
{
786+
return mCurrElem.getAttributeLocalName(index);
787+
}
788+
789+
@Override
790+
public String getAttributeNamespace(int index)
791+
{
792+
return mCurrElem.getAttributeNamespace(index);
793+
}
794+
795+
@Override
796+
public String getAttributePrefix(int index)
797+
{
798+
return mCurrElem.getAttributePrefix(index);
799+
}
800+
801+
@Override
802+
public String getAttributeValue(int index)
803+
{
804+
return mCurrElem.getAttributeValue(index);
805+
}
806+
807+
@Override
808+
public String getAttributeValue(String nsURI, String localName)
809+
{
810+
return mCurrElem.getAttributeValue(nsURI, localName);
811+
}
812+
813+
@Override
814+
public String getAttributeType(int index) {
815+
return (mValidator == null) ? WstxInputProperties.UNKNOWN_ATTR_TYPE :
816+
mValidator.getAttributeType(index);
817+
}
818+
819+
@Override
820+
public int findAttributeIndex(String nsURI, String localName)
821+
{
822+
return mCurrElem.findAttributeIndex(nsURI, localName);
823+
}
824+
825+
/*
826+
///////////////////////////////////////////////////////////////////////
827+
// Overrides to keep the validator up to date in SimpleOutputElement instances
828+
///////////////////////////////////////////////////////////////////////
829+
*/
830+
831+
@Override
832+
public XMLValidator validateAgainst(XMLValidationSchema schema) throws XMLStreamException {
833+
final XMLValidator validateAgainst = super.validateAgainst(schema);
834+
mCurrElem.setValidator(mValidator);
835+
if (mOutputElemPool != null) {
836+
mOutputElemPool.setValidator(mValidator);
837+
}
838+
return validateAgainst;
839+
}
840+
841+
@Override
842+
public XMLValidator stopValidatingAgainst(XMLValidationSchema schema) throws XMLStreamException {
843+
final XMLValidator result = super.stopValidatingAgainst(schema);
844+
mCurrElem.setValidator(mValidator);
845+
if (mOutputElemPool != null) {
846+
mOutputElemPool.setValidator(mValidator);
847+
}
848+
return result;
849+
}
850+
851+
@Override
852+
public XMLValidator stopValidatingAgainst(XMLValidator validator) throws XMLStreamException {
853+
final XMLValidator result = super.stopValidatingAgainst(validator);
854+
mCurrElem.setValidator(mValidator);
855+
if (mOutputElemPool != null) {
856+
mOutputElemPool.setValidator(mValidator);
857+
}
858+
return result;
859+
}
860+
861+
766862
}

0 commit comments

Comments
 (0)