How to get custom attribute value from an XMPP XML

2019-02-13 11:59发布

问题:

Ok guys, simple question but pretty important to me.

so, other android client are sending this xml msg:

<message
  id='6ymdM-19'
  to='xox@xox.xox/smack'
  type='chat'>
  <subject>normal</subject>
  <received xmlns='urn:xmpp:receipts' id='HVgQw-5'/>
</message>

and my listener is roughly like this:

private class MsgListener implements ChatStateListener {
/**
 * Constructor.
 */
public MsgListener() {
}

@Override
public void processMessage(Chat chat, org.jivesoftware.smack.packet.Message message) {
    String xmlMessage = message.toXML();
    Log.v(TAG, "XML Chat: "+xmlMessage);
    // getExtension namespace try urn:xmpp:receipts
    if(xmlMessage.contains("<request xmlns=")) {
        Log.d(TAG, "new chat message arrive! reply with RECEIVED!");
        replyReceived(message);
    } else if(xmlMessage.contains("<received xmlns=")) {
        Log.d(TAG, "RECEIVED notification arrived!");
        PacketExtension statusExtension = 
                message.getExtension("urn:xmpp:receipts");
        Log.d(TAG, "Extension name: "+statusExtension.getElementName());
        Log.d(TAG, "Extension XML: "+statusExtension.toXML());
        Log.d(TAG, "Extension string: "+statusExtension.toString());
    }

     ....
     ....
     ....
} 

in this case I want to get the value of attribute "id", inside the "received" element tag. but what I got on my Log is like this:

RECEIVED notification arrived!
D/ChatAdapter(320): Extension name: received
D/ChatAdapter(320): Extension XML: <received xmlns="urn:xmpp:receipts"></received>
D/ChatAdapter(320): Extension string:              
org.jivesoftware.smack.packet.DefaultPacketExtension@44f10430

So how I can get the 'HVgQw-5' ??

UPDATE

Actually there's something weird... I have receive the xml accordinh from my SMACK debug like this:

 <
 D/SMACK(320): 05:40:28 PM RCV  (1156991856): message id="6ymdM-19"  
 to="syeikh@emass.sangkuriang.co.id/Smack" from="emu22@emass.sangkuriang.co.id/Smack"  
 type="chat"><subject>
 D/SMACK(320): 05:40:28 PM RCV  (1156991856): normal</subject><thread>cr0900</thread>
 **<received xmlns="urn:xmpp:receipts" id="HVgQw-5"/>**<active      
 xmlns="http://jabber.org/protoc
 D/SMACK(320): 05:40:28 PM RCV  (1156991856): ol/chatstates"/></message>

But when I execute message.toXML it's just print out like this:

XML Chat: <message id="6ymdM-19" to="syeikh@emass.sangkuriang.co.id/Smack" from="emu22@emass.sangkuriang.co.id/Smack" type="chat"><subject>normal</subject><thread>cr0900</thread>**<received xmlns="urn:xmpp:receipts">**</received><active xmlns="http://jabber.org/protocol/chatstates" /></message>

Why this is happening? why do I miss the "id" ?

回答1:

About the ID, first get a handle on extension then look for ID, so

DeliveryReceipt deliveryReceiptObj =(DeliveryReceipt) message.getExtension(DeliveryReceipt.NAMESPACE);
// ID below is what you want
deliveryReceiptObj.getId();

Related discussion: asmack - receiving custom XML messages

  1. define your EmbeddedPacketExtension ( so you get a handle on this instead of DefaultPacketExtension provided by SMACK )

  2. A provider that extends EmbeddedExtensionProvider

  3. registerProvider you just created with Namespace

code follows:

/**
* User: suvrat 
* Represents a <b>message delivery receipt</b> entry as specified by
* <a href="http://xmpp.org/extensions/xep-0184.html">Message Delivery Receipts</a>.
*
*/

import org.jivesoftware.smack.packet.PacketExtension;

public class DeliveryReceipt implements PacketExtension
{

    public static final String NAMESPACE = "urn:xmpp:receipts";

    private String id; /// original ID of the delivered message

    public DeliveryReceipt(String id)
    {
        this.id = id;
    }

    public String getId()
    {
        return id;
    }

    public String getElementName()
    {
        return "received";
    }

    public String getNamespace()
    {
        return NAMESPACE;
    }

    public String toXML()
    {
        return "<received xmlns='" + NAMESPACE + "' id='" + id + "'/>";
    }
}

 /**
 * User: suvrat
 * The DeliveryReceiptProvider parses DeliveryReceipt packets.
 */

 */
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.provider.EmbeddedExtensionProvider;
import org.xmlpull.v1.XmlPullParser;

import java.util.List;
import java.util.Map;

public class DeliveryReceiptProvider extends EmbeddedExtensionProvider
{

    @Override
    protected PacketExtension createReturnExtension(String currentElement, String currentNamespace,
    Map<String, String> attributeMap, List<? extends PacketExtension> content)
    {
        return new DeliveryReceipt(attributeMap.get("id"));
    }

}

   //3.) finally where ever you would like to parse packet
 ProviderManager.getInstance().addExtensionProvider("received", DeliveryReceipt.NAMESPACE, new DeliveryReceiptProvider());


回答2:

You can't achieve it without modifying the source code. And the proper approach in XMPP is to create extensions to the standard packets, not modify them. You can refer to Cannot Read Custom Attributes From Message TAG when using asmack XMPP library for android?, which provides the details.



回答3:

There exists another way to get attribute value, which defines the method UserInfo4XMPP by implementing ExtensionElement:

import org.jivesoftware.smack.packet.ExtensionElement;
public class UserInfo4XMPP implements ExtensionElement{
    public static final String NAMESPACE = "urn:xmpp:receipts";
    private String elementName = "received ";
    private String id = "";    
    @Override
    public String getElementName() {
        return elementName;
    }
        @Override
    public CharSequence toXML() {  
        return "<received xmlns='" + NAMESPACE + "' id='" + id + "'/>";
    }
    @Override
    public String getNamespace() {
        return NAMESPACE;
    }
    public String getId()
    {
        return id;
    }
}

The function body is similar to DeliveryReceiptProvider.