Make XHMTMLExtensionProvider use parseElement()

which makes the whole provider much simpler.

Also use CharSequence as Base for XHTML-IM bodies.
This commit is contained in:
Florian Schmaus 2014-07-05 15:04:35 +02:00
parent 94a16ba41e
commit 54b18e3575
5 changed files with 25 additions and 109 deletions

View File

@ -63,8 +63,7 @@ public class PacketParserUtils {
}
public static XmlPullParser getParserFor(Reader reader) throws XmlPullParserException, IOException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
XmlPullParser parser = newXmppParser();
parser.setInput(reader);
// Wind the parser forward to the first start tag

View File

@ -54,7 +54,7 @@ public class XHTMLManager {
* @param message an XHTML message
* @return an Iterator for the bodies in the message or null if none.
*/
public static List<String> getBodies(Message message) {
public static List<CharSequence> getBodies(Message message) {
XHTMLExtension xhtmlExtension = (XHTMLExtension) message.getExtension(XHTMLExtension.ELEMENT, XHTMLExtension.NAMESPACE);
if (xhtmlExtension != null)
return xhtmlExtension.getBodies();

View File

@ -26,14 +26,11 @@ import java.util.List;
/**
* An XHTML sub-packet, which is used by XMPP clients to exchange formatted text. The XHTML
* extension is only a subset of XHTML 1.0.<p>
*
* extension is only a subset of XHTML 1.0.
* <p>
* The following link summarizes the requirements of XHTML IM:
* <a href="http://www.xmpp.org/extensions/jep-0071.html#sect-id2598018">Valid tags</a>.<p>
*
* Warning: this is an non-standard protocol documented by
* <a href="http://www.xmpp.org/extensions/jep-0071.html">XEP-71</a>. Because this is a
* non-standard protocol, it is subject to change.
* <a href="http://www.xmpp.org/extensions/xep-0071.html">XEP-0071: XHTML-IM</a>.
* </p>
*
* @author Gaston Dombiak
*/
@ -42,7 +39,7 @@ public class XHTMLExtension implements PacketExtension {
public static final String ELEMENT = "html";
public static final String NAMESPACE = "http://jabber.org/protocol/xhtml-im";
private List<String> bodies = new ArrayList<String>();
private List<CharSequence> bodies = new ArrayList<CharSequence>();
/**
* Returns the XML element name of the extension sub-packet root element.
@ -85,7 +82,7 @@ public class XHTMLExtension implements PacketExtension {
XmlStringBuilder xml = new XmlStringBuilder(this);
xml.rightAngelBracket();
// Loop through all the bodies and append them to the string buffer
for (String body : getBodies()) {
for (CharSequence body : getBodies()) {
xml.append(body);
}
xml.closeElement(this);
@ -97,9 +94,9 @@ public class XHTMLExtension implements PacketExtension {
*
* @return a List of the bodies in the packet.
*/
public List<String> getBodies() {
public List<CharSequence> getBodies() {
synchronized (bodies) {
return Collections.unmodifiableList(new ArrayList<String>(bodies));
return Collections.unmodifiableList(new ArrayList<CharSequence>(bodies));
}
}
@ -108,7 +105,7 @@ public class XHTMLExtension implements PacketExtension {
*
* @param body the body to add.
*/
public void addBody(String body) {
public void addBody(CharSequence body) {
synchronized (bodies) {
bodies.add(body);
}
@ -120,7 +117,9 @@ public class XHTMLExtension implements PacketExtension {
* @return the number of bodies in the XHTML packet.
*/
public int getBodiesCount() {
return bodies.size();
synchronized (bodies) {
return bodies.size();
}
}
}

View File

@ -1,6 +1,6 @@
/**
*
* Copyright 2003-2007 Jive Software, 2014 Vyacheslav Blinov
* Copyright 2003-2007 Jive Software, 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,7 +19,7 @@ package org.jivesoftware.smackx.xhtmlim.provider;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@ -29,108 +29,27 @@ import java.io.IOException;
/**
* The XHTMLExtensionProvider parses XHTML packets.
*
* @author Vyacheslav Blinov
* @author Florian Schmaus
*/
public class XHTMLExtensionProvider implements PacketExtensionProvider {
@Override
public PacketExtension parseExtension(XmlPullParser parser) throws IOException, XmlPullParserException {
XHTMLExtension xhtmlExtension = new XHTMLExtension();
final String XHTML_EXTENSION_ELEMENT_NAME = xhtmlExtension.getElementName();
int startDepth = parser.getDepth();
int tagDepth = parser.getDepth();
boolean tagStarted = false;
StringBuilder buffer = new StringBuilder();
while (true) {
int eventType = parser.next();
int eventType = parser.getEventType();
String name = parser.getName();
if (eventType == XmlPullParser.START_TAG) {
boolean appendNamespace = false;
if (Message.BODY.equals(parser.getName())) {
buffer = new StringBuilder();
tagDepth = parser.getDepth();
appendNamespace = true;
if (name.equals(Message.BODY)) {
xhtmlExtension.addBody(PacketParserUtils.parseElement(parser));
}
maybeCloseTag(tagStarted, buffer);
appendStartTagPartial(buffer, parser, appendNamespace);
tagStarted = true;
} else if (eventType == XmlPullParser.TEXT) {
tagStarted = maybeCloseTag(tagStarted, buffer);
appendText(buffer, parser);
} else if (eventType == XmlPullParser.END_TAG) {
String name = parser.getName();
if (XHTML_EXTENSION_ELEMENT_NAME.equals(name) && parser.getDepth() <= startDepth) {
if (name.equals(XHTMLExtension.ELEMENT) && parser.getDepth() <= startDepth) {
return xhtmlExtension;
} else {
// xpp does not allows us to detect if tag is self-closing, so we have to
// handle self-closing tags by our own means
appendEndTag(buffer, parser, tagStarted);
tagStarted = false;
if (Message.BODY.equals(name) && parser.getDepth() <= tagDepth) {
xhtmlExtension.addBody(buffer.toString());
}
}
}
parser.next();
}
}
private static void appendStartTagPartial(StringBuilder builder, XmlPullParser parser, boolean withNamespace) {
builder.append('<');
String prefix = parser.getPrefix();
if (StringUtils.isNotEmpty(prefix)) {
builder.append(prefix).append(':');
}
builder.append(parser.getName());
int attributesCount = parser.getAttributeCount();
// handle namespace
if (withNamespace) {
String namespace = parser.getNamespace();
if (StringUtils.isNotEmpty(namespace)) {
builder.append(" xmlns='").append(namespace).append('\'');
}
}
// handle attributes
for (int i = 0; i < attributesCount; ++i) {
builder.append(' ');
String attributeNamespace = parser.getAttributeNamespace(i);
if (StringUtils.isNotEmpty(attributeNamespace)) {
builder.append(attributeNamespace).append(':');
}
builder.append(parser.getAttributeName(i));
String value = parser.getAttributeValue(i);
if (value != null) {
// We need to return valid XML so any inner text needs to be re-escaped
builder.append("='").append(StringUtils.escapeForXML(value)).append('\'');
}
}
}
private static void appendEndTag(StringBuilder builder, XmlPullParser parser, boolean tagStarted) {
if (tagStarted) {
builder.append("/>");
} else {
builder.append("</").append(parser.getName()).append('>');
}
}
private static boolean appendText(StringBuilder builder, XmlPullParser parser) {
String text = parser.getText();
if (text == null) {
return false;
} else {
// We need to return valid XML so any inner text needs to be re-escaped
builder.append(StringUtils.escapeForXML(parser.getText()));
return true;
}
}
private static boolean maybeCloseTag(boolean tagStarted, StringBuilder builder) {
if (tagStarted) {
builder.append('>');
}
return false;
}
}

View File

@ -17,11 +17,11 @@
package org.jivesoftware.smackx.xhtmlim.provider;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
@ -36,8 +36,7 @@ public class XHTMLExtensionProviderTest {
@Test
public void parsesWell() throws IOException, XmlPullParserException {
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
XmlPullParser parser = PacketParserUtils.newXmppParser();
parser.setInput(getClass().getResourceAsStream(XHTML_EXTENSION_SAMPLE_RESOURCE_NAME), "UTF-8");
parser.next();