diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java
index 1ab9cf6ac..97da115d7 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java
@@ -59,6 +59,8 @@ import org.xmlpull.v1.XmlPullParserFactory;
public class PacketParserUtils {
private static final Logger LOGGER = Logger.getLogger(PacketParserUtils.class.getName());
+ public static final String FEATURE_XML_ROUNDTRIP = "http://xmlpull.org/v1/doc/features.html#xml-roundtrip";
+
public static XmlPullParser getParserFor(String stanza) throws XmlPullParserException, IOException {
return getParserFor(new StringReader(stanza));
}
@@ -144,6 +146,12 @@ public class PacketParserUtils {
public static XmlPullParser newXmppParser() throws XmlPullParserException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ try {
+ parser.setFeature(FEATURE_XML_ROUNDTRIP, true);
+ } catch (XmlPullParserException e) {
+ // Doesn't matter if FEATURE_XML_ROUNDTRIP isn't available
+ LOGGER.log(Level.FINEST, "XmlPullParser does not support XML_ROUNDTRIP", e);
+ }
return parser;
}
@@ -368,12 +376,14 @@ public class PacketParserUtils {
* not nested ones, if fullNamespaces
is false. If it is true, then namespaces of
* parent elements will be added to child elements that don't define a different namespace.
*
- * This method is able to parse the content with MX- and KXmlParser. In order to achieve
- * this some trade-off has to be make, because KXmlParser does not support xml-roundtrip (ie.
- * return a String on getText() on START_TAG and END_TAG). We are therefore required to work
- * around this limitation, which results in only partial support for XML namespaces ("xmlns"):
- * Only the outermost namespace of elements will be included in the resulting String, if
- * fullNamespaces
is set to false.
+ * This method is able to parse the content with MX- and KXmlParser. KXmlParser does not support
+ * xml-roundtrip. i.e. return a String on getText() on START_TAG and END_TAG. We check for the
+ * XML_ROUNDTRIP feature. If it's not found we are required to work around this limitation, which
+ * results in only partial support for XML namespaces ("xmlns"): Only the outermost namespace of
+ * elements will be included in the resulting String, if fullNamespaces
is set to false.
+ *
+ * In particular Android's XmlPullParser does not support XML_ROUNDTRIP. *
* * @param parser @@ -384,6 +394,15 @@ public class PacketParserUtils { * @throws IOException */ public static CharSequence parseContentDepth(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException { + if (parser.getFeature(FEATURE_XML_ROUNDTRIP)) { + return parseContentDepthWithRoundtrip(parser, depth, fullNamespaces); + } else { + return parseContentDepthWithoutRoundtrip(parser, depth, fullNamespaces); + } + } + + private static CharSequence parseContentDepthWithoutRoundtrip(XmlPullParser parser, int depth, + boolean fullNamespaces) throws XmlPullParserException, IOException { XmlStringBuilder xml = new XmlStringBuilder(); int event = parser.getEventType(); boolean isEmptyElement = false; @@ -437,6 +456,24 @@ public class PacketParserUtils { return xml; } + private static CharSequence parseContentDepthWithRoundtrip(XmlPullParser parser, int depth, boolean fullNamespaces) + throws XmlPullParserException, IOException { + StringBuilder sb = new StringBuilder(); + int event = parser.getEventType(); + outerloop: while (true) { + // Only append the text if the parser is not on on an empty element' start tag. Empty elements are reported + // twice, so in order to prevent duplication we only add their text when we are on their end tag. + if (!(event == XmlPullParser.START_TAG && parser.isEmptyElementTag())) { + sb.append(parser.getText()); + } + if (event == XmlPullParser.END_TAG && parser.getDepth() <= depth) { + break outerloop; + } + event = parser.next(); + } + return sb; + } + /** * Parses a presence packet. *