11package com .fasterxml .jackson .dataformat .xml .deser ;
22
33import java .io .IOException ;
4+ import java .util .Objects ;
45
56import javax .xml .XMLConstants ;
7+ import javax .xml .namespace .QName ;
68import javax .xml .stream .*;
79
10+ import com .fasterxml .jackson .dataformat .xml .ser .ToXmlGenerator ;
811import org .codehaus .stax2 .XMLStreamLocation2 ;
912import org .codehaus .stax2 .XMLStreamReader2 ;
1013import org .codehaus .stax2 .ri .Stax2ReaderAdapter ;
@@ -73,6 +76,8 @@ public class XmlTokenStream
7376
7477 protected boolean _cfgProcessXsiNil ;
7578
79+ protected boolean _cfgProcessEscapedTag ;
80+
7681 /*
7782 /**********************************************************************
7883 /* Parsing state
@@ -158,6 +163,7 @@ public XmlTokenStream(XMLStreamReader xmlReader, ContentReference sourceRef,
158163 _sourceReference = sourceRef ;
159164 _formatFeatures = formatFeatures ;
160165 _cfgProcessXsiNil = FromXmlParser .Feature .PROCESS_XSI_NIL .enabledIn (_formatFeatures );
166+ _cfgProcessEscapedTag = FromXmlParser .Feature .PROCESS_ESCAPED_MALFORMED_TAGS .enabledIn (_formatFeatures );
161167 _xmlReader = Stax2ReaderAdapter .wrapIfNecessary (xmlReader );
162168 }
163169
@@ -176,7 +182,7 @@ public int initialize() throws XMLStreamException
176182 _localName = _xmlReader .getLocalName ();
177183 _namespaceURI = _xmlReader .getNamespaceURI ();
178184
179- _checkXsiAttributes (); // sets _attributeCount, _nextAttributeIndex
185+ _checkMagicAttributes (); // sets _attributeCount, _nextAttributeIndex
180186
181187 // 02-Jul-2020, tatu: Two choices: if child elements OR attributes, expose
182188 // as Object value; otherwise expose as Text
@@ -220,6 +226,7 @@ public XMLStreamReader2 getXmlReader() {
220226 protected void setFormatFeatures (int f ) {
221227 _formatFeatures = f ;
222228 _cfgProcessXsiNil = FromXmlParser .Feature .PROCESS_XSI_NIL .enabledIn (f );
229+ _cfgProcessEscapedTag = FromXmlParser .Feature .PROCESS_ESCAPED_MALFORMED_TAGS .enabledIn (f );
223230 }
224231
225232 /*
@@ -618,17 +625,14 @@ private final String _getText(XMLStreamReader2 r) throws XMLStreamException
618625
619626 private final int _initStartElement () throws XMLStreamException
620627 {
621- final String ns = _xmlReader .getNamespaceURI ();
622- final String localName = _xmlReader .getLocalName ();
623-
624- _checkXsiAttributes ();
628+ final QName qName = _checkMagicAttributes ();
625629
626630 // Support for virtual wrapping: in wrapping, may either create a new
627631 // wrapper scope (if in sub-tree, or matches wrapper element itself),
628632 // or implicitly close existing scope.
629633
630634 if (_currentWrapper != null ) {
631- if (_currentWrapper .matchesWrapper (localName , ns )) {
635+ if (_currentWrapper .matchesWrapper (qName . getLocalPart (), qName . getNamespaceURI () )) {
632636 _currentWrapper = _currentWrapper .intermediateWrapper ();
633637//System.out.println(" _initStartElement(): START_ELEMENT ("+localName+") DOES match ["+_currentWrapper+"]: leave/add intermediate");
634638 } else {
@@ -638,23 +642,28 @@ private final int _initStartElement() throws XMLStreamException
638642 _namespaceURI = _currentWrapper .getWrapperNamespace ();
639643 _currentWrapper = _currentWrapper .getParent ();
640644 // Important! We also need to restore the START_ELEMENT, so:
641- _nextLocalName = localName ;
642- _nextNamespaceURI = ns ;
645+ _nextLocalName = qName . getLocalPart () ;
646+ _nextNamespaceURI = qName . getNamespaceURI () ;
643647 _repeatElement = REPLAY_START_DELAYED ;
644648 return (_currentState = XML_END_ELEMENT );
645649 }
646650 }
647- _localName = localName ;
648- _namespaceURI = ns ;
651+ _localName = qName . getLocalPart () ;
652+ _namespaceURI = qName . getNamespaceURI () ;
649653 return (_currentState = XML_START_ELEMENT );
650654 }
651655
652656 /**
653657 * @since 2.10
654658 */
655- private final void _checkXsiAttributes () {
659+ protected QName _checkMagicAttributes () {
656660 int count = _xmlReader .getAttributeCount ();
657661 _attributeCount = count ;
662+ _nextAttributeIndex = 0 ;
663+ _xsiNilFound = false ;
664+
665+ String ns = _xmlReader .getNamespaceURI ();
666+ String localName = _xmlReader .getLocalName ();
658667
659668 // [dataformat-xml#354]: xsi:nul handling; at first only if first attribute
660669 if (count >= 1 ) {
@@ -666,13 +675,21 @@ private final void _checkXsiAttributes() {
666675 _nextAttributeIndex = 1 ;
667676 // but only mark as nil marker if enabled
668677 _xsiNilFound = "true" .equals (_xmlReader .getAttributeValue (0 ));
669- return ;
670678 }
671679 }
672680 }
673681
674- _nextAttributeIndex = 0 ;
675- _xsiNilFound = false ;
682+ // Handle PROCESS_ESCAPED_MALFORMED_TAGS
683+ if (count > _nextAttributeIndex && _cfgProcessEscapedTag && localName .equals (ToXmlGenerator .ESCAPED_TAG_NAME )) {
684+ final String attr = _xmlReader .getAttributeLocalName (_nextAttributeIndex );
685+ final String attrNS = _xmlReader .getAttributeNamespace (_nextAttributeIndex );
686+ if (Objects .equals (attrNS , ToXmlGenerator .ESCAPED_ATTR_NS ) && Objects .equals (attr , ToXmlGenerator .ESCAPED_ATTR_NAME )) {
687+ localName = _xmlReader .getAttributeValue (_nextAttributeIndex );
688+ _nextAttributeIndex += 1 ;
689+ }
690+ }
691+
692+ return new QName (ns , localName );
676693 }
677694
678695 /**
0 commit comments