Not logged in. · Lost password · Register
Forum: agsXMPP SDK Support RSS
The namespace handling is not consistent
Avatar
LJN #1
Member since Sep 2006 · 1 post
Group memberships: Members
Show profile · Link to this post
Subject: Issue with namespace support in custom messages.
Hi,
We are experiencing diverse problems with the namespace handling in the StreamParser.

First of all there is only support for one namespace in the Element class and secondly the mapping between custom tags namespaces and possible use of namespace prefixes is not transparent.

i.e.
The namespace in a custom tag and will not match received xml if the received xml uses another namespace prefix and further on all other namespaces will be removed from this Element since there is only support for one namespace in the Element class.

We modified the code to support matching when there is a difference between the namespace prefixes, but support for multiple namespace and preservation of the namespace prefix would be most appreciated.  :-)

Here is the modified code in the streamparser.cs:
private void StartTag(byte[] buf, int offset,
            ContentToken ct, TOK tok)
        {
            m_Depth++;
            int colon;
            string name;
            string prefix;
            Hashtable ht = new Hashtable();           
            m_ns.PushScope();
           
            // if i have attributes
            if ((tok == TOK.START_TAG_WITH_ATTS) ||
                (tok == TOK.EMPTY_ELEMENT_WITH_ATTS))
            {
                int start;
                int end;
                string val;
                for (int i=0; i<ct.getAttributeSpecifiedCount(); i++)
                {                   
                    start =  ct.getAttributeNameStart(i);
                    end = ct.getAttributeNameEnd(i);
                    name = utf.GetString(buf, start, end - start);
                   
                    start = ct.getAttributeValueStart(i);
                    end =  ct.getAttributeValueEnd(i);
                    //val = utf.GetString(buf, start, end - start);

                    val = NormalizeAttributeValue(buf, start, end - start);
                    // <foo b='&amp;'/>
                    // <foo b='&amp;amp;'
                    // TODO: if val includes &amp;, it gets double-escaped
                    if (name.StartsWith("xmlns:"))
                    {
                        colon = name.IndexOf(':');
                        prefix = name.Substring(colon+1);
                        m_ns.AddNamespace(prefix, val);
                       // add other namespaces to list of attributes...
                        ht.Add(name, val);
                    }
                    else if (name == "xmlns")
                    {
                        m_ns.AddNamespace(string.Empty, val);
                    }
                    else
                    {
                        ht.Add(name, val);
                    }
                }
            }

            name = utf.GetString(buf,
                offset + m_enc.MinBytesPerChar,
                ct.NameEnd - offset - m_enc.MinBytesPerChar);
           
            colon = name.IndexOf(':');
            string ns = "";
            prefix = null;
            if (colon > 0)
            {  
                prefix = name.Substring(0, colon);
                name = name.Substring(colon + 1);
                ns = m_ns.LookupNamespace(prefix);
                
               if (ht.ContainsKey("xmlns:" + prefix))
                    ht.Remove("xmlns:" + prefix);

            }
            else
            {
                ns = m_ns.DefaultNamespace;
            }

            //check ns is added as attribute
                        
            Element newel = ElementFactory.GetElement(prefix, name, ns);
           
            foreach (string attrname in ht.Keys)
            {
                newel.SetAttribute(attrname, (string)ht[attrname]);               
            }
           
            if (m_root == null)
            {
                m_root = newel;
                //FireOnDocumentStart(m_root);
                if (OnStreamStart!=null)
                    OnStreamStart(this, m_root);
            }
            else
            {
                if (current != null)
                    current.AddChild(newel);
                current = newel;
            }
        }

Avatar
Alex #2
Member since Feb 2003 · 4245 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
Hello,

here is a small example to explain the idea of the current StreamParser:

if we get this xml from the socket
<stream:stream
       from='example.com'
       id='someid'
       xmlns='jabber:client'
       xmlns:stream='http://etherx.jabber.org/streams'
       version='1.0'>

<message from='juliet@example.com'
              to='romeo@example.net'
              xml:lang='en'>
    <body>Art thou not Romeo, and a Montague?</body>
</message>

</stream:stream>

the StreamParser creates the following xml:
<stream
       from='example.com'
       id='someid'
       xmlns='http://etherx.jabber.org/streams'
       version='1.0'>

<message xmlns='jabber:client'
         from='juliet@example.com'
         to='romeo@example.net'
         xml:lang='en'>
    <body>Art thou not Romeo, and a Montague?</body>
</message>

</stream>

from a xml standpoint both documents are exactly the same. If you compare them as a string or binary they are not, but we care about xml here.

agsXMPP is fully namespace correct, which does not mean that we could improve the XML DOM and the StreamParser. And it's on the very top of our TODO list to make some changes and improvements to the XML stuff.

So all feedback is welcome. Please let us know what you need.

To give you some ideas why we have done it this way:
  • unlike other XMPP implementations we see the whole stream as one XML document, not each stanza as a document.
  • we did not use System.Xml because it's very slow on embedded devices.
  • we did not use System.Xml because you can't create XmlElements without having a document. This means with System.Xml we would have to pass the document in the constructor of each protocol class which we wanted to avoid. I think it's much easier to create packets now.
  • The nametable in System.Xml could increase depending on the XML you route and cause memory leaks.
  • the main goal was to create a lighweigt extremly fast and easy to use parser.

What is on our TODO list for updates:
  • better handling of prefixes and namespaces, it will probably end like your code where all namespace declarations will be simple attributes.
  • improve the serializer to not write unnecessary namespaces
  • Add a simple query language similar to XPath which could be used to observe packets and register callbacks for them.
  • switching namespaces of stanzas. This is important for s2s and component connections on servers where packets are routed thru different namespaces (jabber:client, jabber:server etc...)

Alex
Alexander Gnauck
AG-Software
Close Smaller – Larger + Reply to this post:
Verification code: VeriCode Please enter the word from the image into the text field below. (Type the letters only, lower case is okay.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Special characters:
Forum: agsXMPP SDK Support RSS