mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 22:32:06 +01:00
Make DirectoryRosterStore use elements for whitespace content
If whitespace (e.g. \n \t) needs to be preserved, then XML elements should be used instead of attributes. Since we do this now in DirectoryRosterStore, there is also no longer a need for an specialized StringUtils.escapeForXML(). Also introduce XmlStringBuilder, which should become the default way to implement Packet.toXML() and the like.
This commit is contained in:
parent
6b4c53bfc5
commit
363354f237
3 changed files with 173 additions and 56 deletions
|
@ -28,7 +28,7 @@ import org.jivesoftware.smack.packet.RosterPacket;
|
||||||
import org.jivesoftware.smack.packet.RosterPacket.Item;
|
import org.jivesoftware.smack.packet.RosterPacket.Item;
|
||||||
import org.jivesoftware.smack.util.Base32Encoder;
|
import org.jivesoftware.smack.util.Base32Encoder;
|
||||||
import org.jivesoftware.smack.util.FileUtils;
|
import org.jivesoftware.smack.util.FileUtils;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
import org.xmlpull.v1.XmlPullParserFactory;
|
import org.xmlpull.v1.XmlPullParserFactory;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
@ -189,6 +189,7 @@ public class DirectoryRosterStore implements RosterStore {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String parserName;
|
||||||
String user = null;
|
String user = null;
|
||||||
String name = null;
|
String name = null;
|
||||||
String type = null;
|
String type = null;
|
||||||
|
@ -203,15 +204,31 @@ public class DirectoryRosterStore implements RosterStore {
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
|
parserName = parser.getName();
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
if (eventType == XmlPullParser.START_TAG) {
|
||||||
if (parser.getName().equals("item")) {
|
if (parserName.equals("item")) {
|
||||||
user = parser.getAttributeValue(null, "user");
|
user = name = type = status = null;
|
||||||
name = parser.getAttributeValue(null, "name");
|
|
||||||
type = parser.getAttributeValue(null, "type");
|
|
||||||
status = parser.getAttributeValue(null, "status");
|
|
||||||
}
|
}
|
||||||
if (parser.getName().equals("group")) {
|
else if (parserName.equals("user")) {
|
||||||
String group = parser.getAttributeValue(null, "name");
|
parser.next();
|
||||||
|
user = parser.getText();
|
||||||
|
}
|
||||||
|
else if (parserName.equals("name")) {
|
||||||
|
parser.next();
|
||||||
|
name = parser.getText();
|
||||||
|
}
|
||||||
|
else if (parserName.equals("type")) {
|
||||||
|
parser.next();
|
||||||
|
type = parser.getText();
|
||||||
|
}
|
||||||
|
else if (parserName.equals("status")) {
|
||||||
|
parser.next();
|
||||||
|
status = parser.getText();
|
||||||
|
}
|
||||||
|
else if (parserName.equals("group")) {
|
||||||
|
parser.next();
|
||||||
|
parser.next();
|
||||||
|
String group = parser.getText();
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
groupNames.add(group);
|
groupNames.add(group);
|
||||||
}
|
}
|
||||||
|
@ -222,7 +239,7 @@ public class DirectoryRosterStore implements RosterStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (eventType == XmlPullParser.END_TAG) {
|
else if (eventType == XmlPullParser.END_TAG) {
|
||||||
if (parser.getName().equals("item")) {
|
if (parserName.equals("item")) {
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,30 +288,20 @@ public class DirectoryRosterStore implements RosterStore {
|
||||||
|
|
||||||
|
|
||||||
private boolean addEntryRaw (Item item) {
|
private boolean addEntryRaw (Item item) {
|
||||||
StringBuilder s = new StringBuilder();
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
s.append("<item ");
|
xml.openElement("item");
|
||||||
s.append(StringUtils.xmlAttrib("user", item.getUser()));
|
xml.element("user", item.getUser());
|
||||||
s.append(" ");
|
xml.element("name", item.getName());
|
||||||
if (item.getName() != null) {
|
xml.element("type", item.getItemType());
|
||||||
s.append(StringUtils.xmlAttrib("name", item.getName()));
|
xml.element("status", item.getItemStatus());
|
||||||
s.append(" ");
|
for (String groupName : item.getGroupNames()) {
|
||||||
|
xml.openElement("group");
|
||||||
|
xml.element("groupName", groupName);
|
||||||
|
xml.closeElement("group");
|
||||||
}
|
}
|
||||||
if (item.getItemType() != null) {
|
xml.closeElement("item");
|
||||||
s.append(StringUtils.xmlAttrib("type", item.getItemType().name()));
|
|
||||||
s.append(" ");
|
return FileUtils.writeFile(getBareJidFile(item.getUser()), xml.toString());
|
||||||
}
|
|
||||||
if (item.getItemStatus() != null) {
|
|
||||||
s.append(StringUtils.xmlAttrib("status", item.getItemStatus().toString()));
|
|
||||||
s.append(" ");
|
|
||||||
}
|
|
||||||
s.append(">");
|
|
||||||
for (String group : item.getGroupNames()) {
|
|
||||||
s.append("<group ");
|
|
||||||
s.append(StringUtils.xmlAttrib("name", group));
|
|
||||||
s.append(" />");
|
|
||||||
}
|
|
||||||
s.append("</item>");
|
|
||||||
return FileUtils.writeFile(getBareJidFile(item.getUser()), s.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -283,17 +283,6 @@ public class StringUtils {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representing a XML attribute. The value parameter is escaped as necessary. In particular,
|
|
||||||
* white spaces are encoded as character references, such that they are not replaced by ' ' on parsing.
|
|
||||||
* @param name name of the XML attribute
|
|
||||||
* @param value value of the XML attribute
|
|
||||||
*/
|
|
||||||
public static String xmlAttrib(String name, String value) {
|
|
||||||
return name + "=\"" + escapeForXML(value, true) + "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escapes all necessary characters in the String so that it can be used
|
* Escapes all necessary characters in the String so that it can be used
|
||||||
* in an XML doc.
|
* in an XML doc.
|
||||||
|
@ -301,11 +290,7 @@ public class StringUtils {
|
||||||
* @param string the string to escape.
|
* @param string the string to escape.
|
||||||
* @return the string with appropriate characters escaped.
|
* @return the string with appropriate characters escaped.
|
||||||
*/
|
*/
|
||||||
public static String escapeForXML(String string) {
|
public static String escapeForXML(final String string) {
|
||||||
return escapeForXML(string, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String escapeForXML(final String string, final boolean escapeWhitespace) {
|
|
||||||
if (string == null) {
|
if (string == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -336,14 +321,6 @@ public class StringUtils {
|
||||||
toAppend = APOS_ENCODE;
|
toAppend = APOS_ENCODE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// includes \t, \n, \r
|
|
||||||
if (escapeWhitespace && (ch <= 0x1f || (0x7f <= ch && ch <= 0x9f))) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("&#x");
|
|
||||||
sb.append(String.format("%X", (int) ch));
|
|
||||||
sb.append(';');
|
|
||||||
toAppend = sb;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (toAppend != null) {
|
if (toAppend != null) {
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
|
public class XmlStringBuilder implements Appendable, CharSequence {
|
||||||
|
|
||||||
|
private final StringBuilder sb;
|
||||||
|
|
||||||
|
public XmlStringBuilder() {
|
||||||
|
sb = new StringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing if content is null.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param content
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public XmlStringBuilder element(String name, String content) {
|
||||||
|
if (content == null)
|
||||||
|
return this;
|
||||||
|
openElement(name);
|
||||||
|
escape(content);
|
||||||
|
closeElement(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder element(String name, Enum<?> content) {
|
||||||
|
if (content != null) {
|
||||||
|
element(name, content.name());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder halfOpenElement(String name) {
|
||||||
|
sb.append('<').append(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder openElement(String name) {
|
||||||
|
halfOpenElement(name).append('>');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder closeElement(String name) {
|
||||||
|
sb.append("</").append(name).append('>');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder emptyElementClose() {
|
||||||
|
sb.append("/>");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing if value is null.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public XmlStringBuilder attribute(String name, String value) {
|
||||||
|
if (value == null)
|
||||||
|
return this;
|
||||||
|
sb.append(' ').append(name).append("='");
|
||||||
|
escape(value);
|
||||||
|
sb.append('\'');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder xmlnsAttribute(String value) {
|
||||||
|
attribute("xmlns", value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlStringBuilder escape(String text) {
|
||||||
|
sb.append(StringUtils.escapeForXML(text));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder append(CharSequence csq) {
|
||||||
|
sb.append(csq);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder append(CharSequence csq, int start, int end) {
|
||||||
|
sb.append(csq, start, end);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder append(char c) {
|
||||||
|
sb.append(c);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
return sb.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char charAt(int index) {
|
||||||
|
return sb.charAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence subSequence(int start, int end) {
|
||||||
|
return sb.subSequence(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue