使用 `xmpp` 和 `smack` 从 `vcard` 获取自定义元素

Posted

技术标签:

【中文标题】使用 `xmpp` 和 `smack` 从 `vcard` 获取自定义元素【英文标题】:Get customized element from `vcard` using `xmpp` and `smack` 【发布时间】:2019-03-05 16:39:21 【问题描述】:

我创建了一个带有自定义元素的vcard

<vCard xmlns='vcard-temp'><NICKNAME>nickname</NICKNAME><elementName xmlns='xmlns:custom'><avatar>elementName_avatar_3.png</avatar></elementName></vCard>

当我问这个vcard时,我的结果是:

<iq xmlns='jabber:client' to='602157@peropenfire101.per.local/3r6td85ng7' from='271087@peropenfire101.per.local' id='jA5pI-33' type='result'><vCard xmlns='vcard-temp'><JABBERID>271087@peropenfire101.per.local/4usgw7j7u</JABBERID><NICKNAME>nickname</NICKNAME></vCard></iq>

如您所见,缺少自定义元素。 这是我的要求:

try 
        connection.sendStanzaWithResponseCallback(
                new cdcd(from),
                new StanzaFilter() 
                    @Override
                    public boolean accept(Stanza stanza) 
                        return false;
                    
                ,
                new StanzaListener() 
                    @Override
                    public void processStanza(Stanza packet) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException 
                    
                );
     catch (Exception e) 
        e.printStackTrace();
    

private class cdcd extends Stanza

    private final Jid from;

    public cdcd(Jid from) 
        this.from = from;
    

    @Override
    public String toString() 
        return null;
    

    @Override
    public CharSequence toXML(String enclosingNamespace) 
        return "<iq from=\'"+ from +"\' id='v1' type='get'><vCard xmlns='vcard-temp'/></iq>";
    

我不知道如何解决这个问题。

【问题讨论】:

【参考方案1】:

根据XEP-054不支持vCard DTD的非标准元素的特性,所以你的XMPP服务器忽略它们。

很遗憾,Dawson 的提案并未在 IETF 的标准流程中取得进展。由于现在在时间的迷雾中迷失的原因,Jabber 项目继续使用来自 draft-dawson-vcard-xml-dtd-01 的 DTD,进行了两项小的修改以使其适用于 Jabber 社区(添加 JABBERID 和 DESC元素),但也指定所有大写而不是小写的元素名称,如 Draft-dawson-vcard-xml-dtd-01 中定义的那样。此外,Jabber 社区遵循该草案中关于版本信息的用法(但不是 DTD),包括它作为 vCard 元素的属性而不是子元素。这种格式是在 Jabber 社区中的“vcard-temp”命名空间下实现的。

你可以看到here所有支持的元素。 另见讨论here

【讨论】:

@thorny84 ,我很高兴知道您是如何解决这个问题的。【参考方案2】:

解决了... 我创建了一个扩展 VCardProvider 的新类,并在重写方法 parse 中解析了我的自定义标记

public class CustomVCardProvider extends VCardProvider 

private static final String[] TEL = new String[]
        "VOICE",
        "FAX",
        "PAGER",
        "MSG",
        "CELL",
        "VIDEO",
        "BBS",
        "MODEM",
        "ISDN",
        "PCS",
        "PREF",
;

private static final String[] ADR = new String[]
        "POSTAL",
        "PARCEL",
        "DOM",
        "INTL",
        "PREF",
        "POBOX",
        "EXTADR",
        "STREET",
        "LOCALITY",
        "REGION",
        "PCODE",
        "CTRY",
        "FF",
;

@Override
public VCard parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException 

    VCard vCard = new VCard();
    String name = null;

    outerloop:
    while (true) 
        int eventType = parser.next();
        switch (eventType) 
            case XmlPullParser.START_TAG:
                name = parser.getName();
                switch (name) 
                    case CUSTOM_TAG:
                        parseCustomTag(parser, vCard);
                        break;
                    case "N":
                        parseName(parser, vCard);
                        break;
                    case "ORG":
                        parseOrg(parser, vCard);
                        break;
                    case "TEL":
                        parseTel(parser, vCard);
                        break;
                    case "ADR":
                        parseAddress(parser, vCard);
                        break;
                    case "EMAIL":
                        parseEmail(parser, vCard);
                        break;
                    case "NICKNAME":
                        vCard.setNickName(parser.nextText());
                        break;
                    case "JABBERID":
                        vCard.setJabberId(parser.nextText());
                        break;
                    case "PHOTO":
                        parsePhoto(parser, vCard);
                        break;
                    default:
                        break;
                
                break;
            case XmlPullParser.TEXT:
                if (initialDepth + 1 == parser.getDepth()) 
                    vCard.setField(name, parser.getText());
                
                break;
            case XmlPullParser.END_TAG:
                if (parser.getDepth() == initialDepth) 
                    break outerloop;
                
                break;
            default:
                break;
        
    

    return vCard;

别忘了从原始提供者那里复制所有解析器,并在认证后添加ProviderManager.addIQProvider("vCard", "vcard-temp", new CustomVCardProvider());

【讨论】:

以上是关于使用 `xmpp` 和 `smack` 从 `vcard` 获取自定义元素的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 Smack 4.1 从 Android 连接 apache vysper XMPP 服务器

使用 Smack Android 将字符串转换为 XMPP 节

如何为 xmpp 实现 smack

android中的XMPP连接使用smack

使用 Openfire 服务器和 XMPP(SMACK)客户端的 Android 聊天应用程序 [关闭]

收到消息时通知 XMPP + Smack