<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://microformats.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Newacct</id>
	<title>Microformats Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://microformats.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Newacct"/>
	<link rel="alternate" type="text/html" href="https://microformats.org/wiki/Special:Contributions/Newacct"/>
	<updated>2026-04-17T05:37:44Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.38.4</generator>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=43014</id>
		<title>xoxo-sample-code-fr</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=43014"/>
		<updated>2010-08-29T18:27:14Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Code Echantillon =&lt;br /&gt;
&lt;br /&gt;
Un paquet général de code échantillon open source, ([http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0]) pour lire et écrire des fichiers [[xoxo-fr|xoxo]] en Python et Java (avec Perl, PHP, ... à suivre).&lt;br /&gt;
= Python =&lt;br /&gt;
== xoxo.py ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;xoxo.py - a utility module for transforming to and from the XHTMLOutlines format XOXO http://microformats.org/wiki/xoxo&lt;br /&gt;
toXOXO takes a Python datastructure (tuples, lists or dictionaries, arbitrarily nested) and returns a XOXO representation of it.&lt;br /&gt;
fromXOXO parses an XHTML file for a xoxo list and returns the structure&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__version__ = &amp;quot;0.9&amp;quot;&lt;br /&gt;
__date__ = &amp;quot;2005-11-02&amp;quot;&lt;br /&gt;
__author__ = &amp;quot;Kevin Marks &amp;lt;kmarks@technorati.com&amp;gt;&amp;quot;&lt;br /&gt;
__copyright__ = &amp;quot;Copyright 2004-2006, Kevin Marks &amp;amp; Technorati&amp;quot;&lt;br /&gt;
__license__ = &amp;quot;http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0&amp;quot;&lt;br /&gt;
__credits__ = &amp;quot;&amp;quot;&amp;quot;Tantek Çelik and Mark Pilgrim for data structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__history__ = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
TODO: add &amp;lt;title&amp;gt; tag&lt;br /&gt;
TODO: add a proper profile link&lt;br /&gt;
0.9 smarter parsing for encoding and partial markup; fix dangling dictionary case&lt;br /&gt;
0.8 work in unicode then render to utf-8&lt;br /&gt;
0.7 initial encoding support - just utf-8 for now&lt;br /&gt;
0.6 support the special behavior for url properties  to/from &amp;lt;a&amp;gt;&lt;br /&gt;
0.5 fix some awkward side effects of whitespace and text outside our expected tags; simplify writing code&lt;br /&gt;
0.4 add correct XHTML headers so it validates&lt;br /&gt;
0.3 read/write version; fixed invalid nested list generation;&lt;br /&gt;
0.1 first write-only version&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    True, False&lt;br /&gt;
except NameError:&lt;br /&gt;
    True, False = not not 1, not 1&lt;br /&gt;
containerTags={'ol':False,'ul':False,'dl':False}&lt;br /&gt;
import sgmllib, urllib, urlparse, re,codecs&lt;br /&gt;
&lt;br /&gt;
def toUnicode(key):&lt;br /&gt;
    if type(key) == type(u'unicode'):&lt;br /&gt;
        uKey= key&lt;br /&gt;
    else:&lt;br /&gt;
        try: &lt;br /&gt;
            uKey=unicode(key,'utf-8')&lt;br /&gt;
        except:&lt;br /&gt;
            uKey=unicode(key,'windows_1252')&lt;br /&gt;
    return uKey&lt;br /&gt;
&lt;br /&gt;
def makeXOXO(struct,className=None):&lt;br /&gt;
    s=u''&lt;br /&gt;
    if isinstance(struct,(list,tuple)):&lt;br /&gt;
        if className:&lt;br /&gt;
            s += u'&amp;lt;ol class=&amp;quot;%s&amp;quot;&amp;gt;' % className&lt;br /&gt;
        else:&lt;br /&gt;
            s+= u&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;&lt;br /&gt;
        for item in struct:&lt;br /&gt;
            s+=u&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,None)+&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
        s +=u&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;br /&gt;
    elif isinstance(struct,dict):&lt;br /&gt;
        d=struct.copy()&lt;br /&gt;
        if 'url' in d:&lt;br /&gt;
            uURL=toUnicode(d['url'])&lt;br /&gt;
            s+=u'&amp;lt;a href=&amp;quot;%s&amp;quot; ' % uURL&lt;br /&gt;
            text =  d.get('text',d.get('title',uURL))&lt;br /&gt;
            for attr in ('title','rel','type'):&lt;br /&gt;
                if attr in d:&lt;br /&gt;
                    xVal = makeXOXO(d[attr],None)&lt;br /&gt;
                    s +=u'%s=&amp;quot;%s&amp;quot; ' % (attr,xVal)&lt;br /&gt;
                    del d[attr]&lt;br /&gt;
            s +=u'&amp;gt;%s&amp;lt;/a&amp;gt;' % makeXOXO(text,None)&lt;br /&gt;
            if 'text' in d:&lt;br /&gt;
                del d['text']&lt;br /&gt;
            del d['url']&lt;br /&gt;
        if len(d):&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;&lt;br /&gt;
            for key,value in d.items():&lt;br /&gt;
                xVal = makeXOXO(value,None)&lt;br /&gt;
                uKey=toUnicode(key)&lt;br /&gt;
                s+= u'&amp;lt;dt&amp;gt;%s&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;%s&amp;lt;/dd&amp;gt;' % (uKey, xVal)&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
    elif type(struct) == type(u'unicode'):&lt;br /&gt;
        s+=struct&lt;br /&gt;
    else:&lt;br /&gt;
        if type(struct)!=type(' '):&lt;br /&gt;
            struct=str(struct)&lt;br /&gt;
        s += toUnicode(struct)&lt;br /&gt;
    return s&lt;br /&gt;
class AttrParser(sgmllib.SGMLParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        sgmllib.SGMLParser.__init__(self)&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.encoding='utf-8'&lt;br /&gt;
    def cleanText(self,inText):&lt;br /&gt;
        if type(inText) == type(u'unicode'):&lt;br /&gt;
            inText = inText.encode(self.encoding,'replace')&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.reset()&lt;br /&gt;
        self.feed(inText)&lt;br /&gt;
        return ''.join(self.text)&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        if 'ascii' in encoding:&lt;br /&gt;
            encoding='windows_1252' # so we don't throw an exception on high-bit set chars in there by mistake&lt;br /&gt;
        if encoding and not encoding =='text/html':&lt;br /&gt;
            try:&lt;br /&gt;
                canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                self.encoding = encoding&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    encoding='japanese.' +encoding&lt;br /&gt;
                    canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                    self.encoding = encoding&lt;br /&gt;
                except:&lt;br /&gt;
                    print &amp;quot;can't deal with encoding %s&amp;quot; % encoding&lt;br /&gt;
                    &lt;br /&gt;
    def handle_entityref(self, ref):&lt;br /&gt;
        # called for each entity reference, e.g. for &amp;quot;&amp;amp;copy;&amp;quot;, ref will be &amp;quot;copy&amp;quot;&lt;br /&gt;
        # map through to unicode where we can&lt;br /&gt;
        try:&lt;br /&gt;
            entity =htmlentitydefs.name2codepoint[ref]&lt;br /&gt;
            self.handleUnicodeData(unichr(entity))&lt;br /&gt;
        except:&lt;br /&gt;
            try:&lt;br /&gt;
                handle_charref(ref) # deal with char-ref's missing the '#' (see Akma)&lt;br /&gt;
            except:&lt;br /&gt;
                self.handle_data(&amp;quot;&amp;amp;%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
    def handle_charref(self, ref):&lt;br /&gt;
        # called for each character reference, e.g. for &amp;quot;&amp;amp;#160;&amp;quot;, ref will be &amp;quot;160&amp;quot;&lt;br /&gt;
        # Reconstruct the original character reference.&lt;br /&gt;
        try:&lt;br /&gt;
            if ref[0]=='x':&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref[1:],16)))&lt;br /&gt;
            else:&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref)))&lt;br /&gt;
        except:&lt;br /&gt;
            self.handle_data(&amp;quot;&amp;amp;#%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
# called for each block of plain text, i.e. outside of any tag and&lt;br /&gt;
# not containing any character or entity references&lt;br /&gt;
    def handle_data(self, text):&lt;br /&gt;
        if type(text)==type(u' '):&lt;br /&gt;
            self.handleUnicodeData(text)&lt;br /&gt;
        if self.encoding== 'utf-8':&lt;br /&gt;
            try:&lt;br /&gt;
                uText = unicode(text,self.encoding) #utf-8 is pretty clear when it is wrong&lt;br /&gt;
            except:&lt;br /&gt;
                uText = unicode(text,'windows_1252','ignore') # and this is the likely wrongness&lt;br /&gt;
        else:&lt;br /&gt;
            uText = unicode(text,self.encoding,'replace') # if they have really broken encoding, (eg lots of shift-JIS blogs)&lt;br /&gt;
        self.handleUnicodeData(uText)&lt;br /&gt;
    def handleUnicodeData(self, uText):&lt;br /&gt;
        self.text.append(uText)&lt;br /&gt;
        &lt;br /&gt;
class xoxoParser(AttrParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        AttrParser.__init__(self)&lt;br /&gt;
        self.structs=[]&lt;br /&gt;
        self.xostack=[]&lt;br /&gt;
        self.textstack=['']&lt;br /&gt;
        self.attrparse = AttrParser()&lt;br /&gt;
    def normalize_attrs(self, attrs):&lt;br /&gt;
        attrs = [(k.lower(), self.attrparse.cleanText(v)) for k, v in attrs]&lt;br /&gt;
        attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs]&lt;br /&gt;
        return attrs&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        AttrParser.setEncoding(self,encoding)&lt;br /&gt;
        self.attrparse.setEncoding(encoding)&lt;br /&gt;
    def pushStruct(self,struct):&lt;br /&gt;
        if type(struct) == type({}) and len(struct)==0 and len(self.structs) and type(self.structs[-1]) == type({}) and 'url' in self.structs[-1] and self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            self.xostack.append(self.structs[-1]) # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
        else:&lt;br /&gt;
            self.structs.append(struct)&lt;br /&gt;
            self.xostack.append(self.structs[-1])&lt;br /&gt;
    def do_meta(self, attributes):&lt;br /&gt;
        atts = dict(self.normalize_attrs(attributes))&lt;br /&gt;
        #print atts.encode('utf-8')&lt;br /&gt;
        if 'http-equiv' in atts:&lt;br /&gt;
            if atts['http-equiv'].lower() == &amp;quot;content-type&amp;quot;:&lt;br /&gt;
                if 'content' in atts:&lt;br /&gt;
                    encoding = atts['content'].split('charset=')[-1]&lt;br /&gt;
                    self.setEncoding(encoding)&lt;br /&gt;
    def start_a(self,attrs):&lt;br /&gt;
        attrsD = dict(self.normalize_attrs(attrs))&lt;br /&gt;
        attrsD['url']= attrsD.get('href','')&lt;br /&gt;
        if 'href' in attrsD:&lt;br /&gt;
            del attrsD['href']&lt;br /&gt;
        self.pushStruct(attrsD)&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_a(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        if val: &lt;br /&gt;
            if self.xostack[-1].get('title','') == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if self.xostack[-1]['url'] == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if val:&lt;br /&gt;
                self.xostack[-1]['text']=val&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_dl(self,attrs):&lt;br /&gt;
        self.pushStruct({})&lt;br /&gt;
    def end_dl(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ol(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ol(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ul(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ul(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_li(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_li(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        while self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
        if type(val) == type(' ') or type(val) == type(u' '):&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
    def start_dt(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dt(self):&lt;br /&gt;
        pass&lt;br /&gt;
    def start_dd(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dd(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        key = self.textstack.pop()&lt;br /&gt;
        if self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
        self.xostack[-1][key]=val&lt;br /&gt;
    def handleUnicodeData(self, text):&lt;br /&gt;
        if len(self.stack) and containerTags.get(self.stack[-1],True): #skip text not within an element&lt;br /&gt;
            self.textstack[-1] += text&lt;br /&gt;
def toXOXO(struct,addHTMLWrapper=False,cssUrl=''):&lt;br /&gt;
    if type(struct) ==type((1,))or type(struct) ==type([1,]):&lt;br /&gt;
        inStruct = struct&lt;br /&gt;
    else:&lt;br /&gt;
        inStruct = [struct]&lt;br /&gt;
    if addHTMLWrapper:&lt;br /&gt;
        s= u'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;'''&lt;br /&gt;
        if cssUrl:&lt;br /&gt;
            s+=u'&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;%s&amp;quot;;&amp;lt;/style&amp;gt;' % cssUrl&lt;br /&gt;
        s+=u&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot; % makeXOXO(inStruct,'xoxo')&lt;br /&gt;
        return s.encode('utf-8')&lt;br /&gt;
    else:&lt;br /&gt;
        return makeXOXO(inStruct,'xoxo').encode('utf-8')&lt;br /&gt;
    &lt;br /&gt;
def fromXOXO(html):&lt;br /&gt;
    parser = xoxoParser()&lt;br /&gt;
    #parser.feed(unicode(html,'utf-8'))&lt;br /&gt;
    parser.feed(html)&lt;br /&gt;
    #print parser.structs&lt;br /&gt;
    structs=[struct for struct in parser.structs if struct]&lt;br /&gt;
    #print structs&lt;br /&gt;
    while len(structs) ==1 and type(structs)==type([1,]):&lt;br /&gt;
        structs=structs[0]&lt;br /&gt;
    return structs&lt;br /&gt;
&lt;br /&gt;
# Allow direct invocation&lt;br /&gt;
# Read HTML from URL, parse into data structures, then re-output&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  if len(sys.argv) &amp;lt; 2: raise SystemExit(&amp;quot;Usage: &amp;quot;+sys.argv[0]+&amp;quot; url\n&amp;quot;+__doc__)&lt;br /&gt;
  url=sys.argv[1]&lt;br /&gt;
  file = urllib.urlopen(url)&lt;br /&gt;
  html=file.read(-1)&lt;br /&gt;
  file.close&lt;br /&gt;
  s=fromXOXO(html)&lt;br /&gt;
  p=toXOXO(s,True)&lt;br /&gt;
  print p&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== testxoxo.py  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;testxoxo.py &lt;br /&gt;
Unit tests for xoxo.py&lt;br /&gt;
This file tests the functions in xoxo.py &lt;br /&gt;
The underlying model here is http://diveintopython.org/unit_testing/index.html &lt;br /&gt;
&lt;br /&gt;
run from command line with&lt;br /&gt;
python testxoxo.py -v&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import xoxo&lt;br /&gt;
reload(xoxo)&lt;br /&gt;
import unittest&lt;br /&gt;
&lt;br /&gt;
class xoxoTestCases(unittest.TestCase):&lt;br /&gt;
    &lt;br /&gt;
    def testSimpleList(self):&lt;br /&gt;
        '''make a xoxo file from a list'''&lt;br /&gt;
        l = ['1','2','3']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
    def testNestedList(self):&lt;br /&gt;
        '''make a xoxo file from a list with a list in'''&lt;br /&gt;
        l = ['1',['2','3']]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testDictionary(self):&lt;br /&gt;
        '''make a xoxo file from a dictionary'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testSingleItem(self):&lt;br /&gt;
        '''make a xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testWrapDiffers(self):&lt;br /&gt;
        '''make a xoxo file from a string with and without html wrapper and check they are different'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        htmlwrap =  xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.failIfEqual(html,htmlwrap)&lt;br /&gt;
&lt;br /&gt;
    def testWrapSingleItem(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testWrapItemWithCSS(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True,cssUrl='reaptest.css')&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
        &lt;br /&gt;
    def testDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary wiht an url in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)    &lt;br /&gt;
    def testNestedDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with a dict in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionariesWithURLsRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict with an url into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin','url':'http://slashdot.org'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testListRoundTrip(self):&lt;br /&gt;
        ''' make a list into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3','2','1']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofDictsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Dicts into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',{'a':'2'},{'b':'1','c':'4'}]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofListsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Lists into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',['a','2'],['b',['1',['c','4']]]]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testDictofListsRoundTrip(self):&lt;br /&gt;
        ''' make a dict with lists in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':['1','2'],&lt;br /&gt;
        'name':'Kevin',&lt;br /&gt;
        'nestlist':['a',['b','c']],&lt;br /&gt;
        'nestdict':{'e':'6','f':'7'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInContainers(self):&lt;br /&gt;
        '''make sure text outside &amp;lt;li&amp;gt; etc is ignored'''&lt;br /&gt;
        d=xoxo.fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(d,{'good': 'buy'})&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInElements(self):&lt;br /&gt;
        '''make sure text within &amp;lt;li&amp;gt; but outside a subcontainer is ignored'''&lt;br /&gt;
        l=xoxo.fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(l,[{'good': 'buy'},['OK']])&lt;br /&gt;
&lt;br /&gt;
    def testXOXOWithSpacesAndNewlines(self):&lt;br /&gt;
        '''unmung some xoxo with spaces in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        d2={'text':'item 1',&lt;br /&gt;
            'description':&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
            'url':'http://example.com/more.xoxo',&lt;br /&gt;
            'title':'title of item 1',&lt;br /&gt;
            'type':'text/xml',&lt;br /&gt;
            'rel':'help'&lt;br /&gt;
            }&lt;br /&gt;
        xoxoAgain = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        #this needs a smarter whitespace-sensitive comparison&lt;br /&gt;
        #self.assertEqual(xoxoSample,xoxoAgain)&lt;br /&gt;
&lt;br /&gt;
    def testSpecialAttributeDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeAndDLDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in plus a &amp;lt;dl&amp;gt; in the same item and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeEncode(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        expectedHTML= '&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;' &lt;br /&gt;
        self.assertEqual(html,expectedHTML)&lt;br /&gt;
        &lt;br /&gt;
    def testSpecialAttributeRoundTripFull(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoText(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoTextOrTitle(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text or title attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testAttentionRoundTrip(self):&lt;br /&gt;
        '''check nested &amp;lt;a&amp;gt; and &amp;lt;dl&amp;gt; and &amp;lt;a&amp;gt; are preserved'''&lt;br /&gt;
        kmattn='''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;''';&lt;br /&gt;
        d = xoxo.fromXOXO(kmattn)&lt;br /&gt;
        newattn = xoxo.toXOXO(d)&lt;br /&gt;
        d2 = xoxo.fromXOXO(newattn)&lt;br /&gt;
        self.assertEqual(newattn,xoxo.toXOXO(d2))&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        self.assertEqual(kmattn,newattn)&lt;br /&gt;
        &lt;br /&gt;
    def testUnicodeRoundtrip(self):&lt;br /&gt;
        '''check unicode characters can go to xoxo and back'''&lt;br /&gt;
        src=unicode('Tantek \xc3\x87elik and a snowman \xe2\x98\x83','utf-8')&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html))&lt;br /&gt;
    def testUtf8Roundtrip(self):&lt;br /&gt;
        '''check utf8 characters can go to xoxo and back'''&lt;br /&gt;
        src='Tantek \xc3\x87elik and a snowman \xe2\x98\x83'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('utf-8'))&lt;br /&gt;
    def testWindows1252Roundtrip(self):&lt;br /&gt;
        '''check 1252 characters can go to xoxo and back'''&lt;br /&gt;
        src='This is an evil\xa0space'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('windows-1252'))&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    unittest.main()&lt;br /&gt;
else:&lt;br /&gt;
    runner = unittest.TextTestRunner()&lt;br /&gt;
    suite = unittest.makeSuite(xoxoTestCases,'test')&lt;br /&gt;
    runner.run(suite)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Java =&lt;br /&gt;
== XOXOWriter.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOWriter {&lt;br /&gt;
&lt;br /&gt;
  public String[] attrs = {&amp;quot;title&amp;quot;,&amp;quot;rel&amp;quot;,&amp;quot;type&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className){&lt;br /&gt;
    return makeXOXO(struct, className, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className,&lt;br /&gt;
                         boolean doNSDeclaration){&lt;br /&gt;
    return makeXOXO(struct, className, 0, doNSDeclaration);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct){&lt;br /&gt;
    return makeXOXO(struct, &amp;quot;xoxo&amp;quot;, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, int depth){&lt;br /&gt;
    return makeXOXO(struct, null, 0, false);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, String className,&lt;br /&gt;
                         int depth, boolean doNSDeclaration){&lt;br /&gt;
    if(struct == null) return &amp;quot;&amp;quot;;&lt;br /&gt;
    StringBuffer sb = new StringBuffer();&lt;br /&gt;
    if(struct instanceof Object[]){&lt;br /&gt;
      struct = Arrays.asList((Object[]) struct);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof List){&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;ol&amp;quot;);&lt;br /&gt;
      if(doNSDeclaration)&lt;br /&gt;
        sb.append(&amp;quot; xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;quot;);&lt;br /&gt;
      if(className != null){&lt;br /&gt;
        sb.append(&amp;quot; class=\&amp;quot;&amp;quot;);&lt;br /&gt;
        sb.append(className);&lt;br /&gt;
        sb.append(&amp;quot;\&amp;quot;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof Map){&lt;br /&gt;
      Map d = new LinkedHashMap((Map) struct);&lt;br /&gt;
      if(d.containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;a href=\&amp;quot;&amp;quot; + d.get(&amp;quot;url&amp;quot;) + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
        Object text;&lt;br /&gt;
        if(d.containsKey(&amp;quot;text&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;text&amp;quot;);&lt;br /&gt;
        }else if(d.containsKey(&amp;quot;title&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
          text = d.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        for(int i=0; i&amp;lt;attrs.length; i++){&lt;br /&gt;
          String xVal = makeXOXO(d.get(attrs[i]),depth+1);&lt;br /&gt;
          if(xVal != null &amp;amp;&amp;amp; !xVal.equals(&amp;quot;&amp;quot;)){&lt;br /&gt;
            sb.append(attrs[i] + &amp;quot;=\&amp;quot;&amp;quot; + xVal + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
          d.remove(attrs[i]);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;gt;&amp;quot; + makeXOXO(text, depth+1) + &amp;quot;&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;text&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;url&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      if(d.size() &amp;gt; 0){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;);&lt;br /&gt;
        for(Iterator i = d.entrySet().iterator(); i.hasNext();){&lt;br /&gt;
          Map.Entry entry = (Map.Entry)i.next();&lt;br /&gt;
          String ddVal = makeXOXO(entry.getValue(),depth+1);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dt&amp;gt;&amp;quot; + entry.getKey() + &amp;quot;&amp;lt;/dt&amp;gt;&amp;quot;);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dd&amp;gt;&amp;quot; + ddVal + &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
    }else if(struct instanceof List){&lt;br /&gt;
      List l = (List) struct;&lt;br /&gt;
      for(Iterator i = l.iterator(); i.hasNext();){&lt;br /&gt;
        Object item = i.next();&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,depth+1) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);&lt;br /&gt;
    }else{&lt;br /&gt;
      sb.append(struct);&lt;br /&gt;
    }&lt;br /&gt;
    return sb.toString();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct){&lt;br /&gt;
    return toXOXO(struct, false, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist, addHTMLWrapper, cssUrl);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;quot;;&lt;br /&gt;
    if(addHTMLWrapper){&lt;br /&gt;
      String s = startHTML;&lt;br /&gt;
      if(cssUrl != null){&lt;br /&gt;
        s += &amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot;&amp;gt;@import \&amp;quot;&amp;quot;&lt;br /&gt;
            + cssUrl + &amp;quot;\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      s += &amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot; + makeXOXO(struct, &amp;quot;xoxo&amp;quot;, false)&lt;br /&gt;
          + &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
      return s;&lt;br /&gt;
    }else{&lt;br /&gt;
      return makeXOXO(struct, &amp;quot;xoxo&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOParser.java ==&lt;br /&gt;
Ceci a besoin de quelques petits ajouts pour gérer les entités XHTML DTD et digits nommés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import org.xml.sax.InputSource;&lt;br /&gt;
import org.xml.sax.SAXException;&lt;br /&gt;
import org.xml.sax.XMLReader;&lt;br /&gt;
import org.xml.sax.Attributes;&lt;br /&gt;
import org.xml.sax.helpers.XMLReaderFactory;&lt;br /&gt;
import org.xml.sax.helpers.DefaultHandler;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
import java.io.InputStream;&lt;br /&gt;
import java.io.StringReader;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
&lt;br /&gt;
public class XOXOParser extends DefaultHandler {&lt;br /&gt;
&lt;br /&gt;
  protected String XHTML_NS = &amp;quot;http://www.w3.org/1999/xhtml&amp;quot;;&lt;br /&gt;
  protected List elStack;&lt;br /&gt;
  protected Map listEls;&lt;br /&gt;
  public List structs;&lt;br /&gt;
  public List xoStack;&lt;br /&gt;
  public List textStack;&lt;br /&gt;
&lt;br /&gt;
  public XOXOParser() {&lt;br /&gt;
    reset();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void pushStruct(Object struct){&lt;br /&gt;
    if(struct instanceof Map &amp;amp;&amp;amp; !((Map) struct).isEmpty()&lt;br /&gt;
        &amp;amp;&amp;amp; structs.get(structs.size()-1) instanceof Map&lt;br /&gt;
        &amp;amp;&amp;amp; ((Map) struct).containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
      // put back the &amp;lt;a&amp;gt;-made one for extra defs&lt;br /&gt;
      xoStack.add(structs.get(structs.size()-1));&lt;br /&gt;
    }else{&lt;br /&gt;
      structs.add(struct);&lt;br /&gt;
      xoStack.add(struct);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void startElement(String nsUri, String localName,&lt;br /&gt;
                           String qName, Attributes atts){&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri.equals(XHTML_NS)){&lt;br /&gt;
      elStack.add(localName);&lt;br /&gt;
    }else{&lt;br /&gt;
      elStack.add(&amp;quot;foo&amp;quot;);&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      Map attmap = new LinkedHashMap();&lt;br /&gt;
      int len = atts.getLength();&lt;br /&gt;
      for(int i=0; i&amp;lt;len; i++){&lt;br /&gt;
        attmap.put(atts.getQName(i),atts.getValue(i));&lt;br /&gt;
      }&lt;br /&gt;
      if(attmap.containsKey(&amp;quot;href&amp;quot;)){&lt;br /&gt;
        attmap.put(&amp;quot;url&amp;quot;,attmap.get(&amp;quot;href&amp;quot;));&lt;br /&gt;
        attmap.remove(&amp;quot;href&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      pushStruct(attmap);&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      pushStruct(new LinkedHashMap());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dt&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void endElement(String nsUri, String localName,&lt;br /&gt;
                         String qName){&lt;br /&gt;
    elStack.remove(elStack.size()-1);&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri != XHTML_NS){&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      String val = (String) textStack.remove(textStack.size()-1);&lt;br /&gt;
      if (val.length() &amp;gt; 0){&lt;br /&gt;
        Map defs = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
        String defVal = (String) defs.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        if(defVal != null &amp;amp;&amp;amp; val.equals(defVal)){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        defVal = (String) defs.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        if(defVal != null &amp;amp;&amp;amp; val.equals(defVal)){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        if(val.length() &amp;gt; 0){&lt;br /&gt;
          defs.put(&amp;quot;text&amp;quot;,val);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      List last = (List) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.add(val);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Object key = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Map last = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.put(key,val);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void characters(char[] ch, int start, int length){&lt;br /&gt;
    if(xoStack.size() &amp;gt; 0&lt;br /&gt;
        &amp;amp;&amp;amp; !listEls.containsKey(elStack.get(elStack.size()-1))){&lt;br /&gt;
      String text = (String) textStack.get(textStack.size()-1);&lt;br /&gt;
      String test = new String(ch,start,length);&lt;br /&gt;
      textStack.set(textStack.size()-1,text+test);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(String s) throws SAXException, IOException{&lt;br /&gt;
    return parse(new InputSource(new StringReader(s)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputStream is) throws SAXException, IOException {&lt;br /&gt;
    return parse(new InputSource(is));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputSource in) throws SAXException, IOException {&lt;br /&gt;
    XMLReader parser = XMLReaderFactory.createXMLReader();&lt;br /&gt;
    parser.setContentHandler(this);&lt;br /&gt;
    parser.parse(in);&lt;br /&gt;
    List returnList = new ArrayList();&lt;br /&gt;
    for(Iterator i = this.structs.iterator(); i.hasNext();){&lt;br /&gt;
      Object thing = i.next();&lt;br /&gt;
      if(thing != null){&lt;br /&gt;
        returnList.add(thing);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    while(returnList.size()==1){&lt;br /&gt;
      if(returnList.get(0) instanceof List){&lt;br /&gt;
        returnList = (List) returnList.get(0);&lt;br /&gt;
      }else{&lt;br /&gt;
        reset();&lt;br /&gt;
        return returnList.get(0);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    reset();&lt;br /&gt;
    return returnList;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void reset(){&lt;br /&gt;
    elStack = new ArrayList();&lt;br /&gt;
    listEls = new HashMap();&lt;br /&gt;
    structs = new ArrayList();&lt;br /&gt;
    xoStack = new ArrayList();&lt;br /&gt;
    textStack = new ArrayList();&lt;br /&gt;
    listEls.put(&amp;quot;ol&amp;quot;,&amp;quot;ol&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;ul&amp;quot;,&amp;quot;ul&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;dl&amp;quot;,&amp;quot;dl&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOTest.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo.tests;&lt;br /&gt;
&lt;br /&gt;
import junit.framework.TestSuite;&lt;br /&gt;
import junit.framework.TestCase;&lt;br /&gt;
import junit.textui.TestRunner;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOWriter;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOParser;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOTest extends TestCase {&lt;br /&gt;
&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    new TestRunner().doRun(new TestSuite(XOXOTest.class));&lt;br /&gt;
  }&lt;br /&gt;
  String XHTML_DEC = &amp;quot;xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot; &amp;quot;;&lt;br /&gt;
  public String simpleListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSimpleList(){&lt;br /&gt;
    String [] numbers = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testStringIntegerList(){&lt;br /&gt;
    Object[] numbers = {new Integer(1),&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String nestedListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testNestedList(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,Arrays.asList(arr)};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testNestedArray(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,arr};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String dictHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testDictionary(){&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, new Integer(1));&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(dictHTML,&lt;br /&gt;
                 xoxo.toXOXO(dict));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String singleHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(singleHTML,&lt;br /&gt;
                 xoxo.toXOXO(item));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testWrapDiffers(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String nowrap = xoxo.toXOXO(item);&lt;br /&gt;
    Object[] itemArr = {item};&lt;br /&gt;
    String wrap = xoxo.toXOXO(Arrays.asList(itemArr),true,null);&lt;br /&gt;
    assertFalse(wrap.equals(nowrap));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;;&lt;br /&gt;
  public String singleWrapHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
  public String endHTML = &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testWrapSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(startHTML + singleWrapHTML + endHTML,&lt;br /&gt;
                 xoxo.toXOXO(item,true,null));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOParser(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      parser.parse(dictHTML);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
     try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListRoundTrip(){&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfDictsRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    Map dict2 = new LinkedHashMap();&lt;br /&gt;
    dict2.put(&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;three&amp;quot;, &amp;quot;four&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;five&amp;quot;, &amp;quot;six&amp;quot;);&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,dict,dict2};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;, Arrays.asList(list1)};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;, Arrays.asList(list2)};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, Arrays.asList(list3)};&lt;br /&gt;
    List testList = Arrays.asList(list4);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, &amp;quot;9&amp;quot;};&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;foo&amp;quot;, Arrays.asList(list1));&lt;br /&gt;
    dict.put(&amp;quot;bar&amp;quot;, Arrays.asList(list2));&lt;br /&gt;
    dict.put(&amp;quot;baz&amp;quot;, Arrays.asList(list3));&lt;br /&gt;
    dict.put(&amp;quot;qux&amp;quot;, Arrays.asList(list4));&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOJunkInContainers(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(junkXOXO);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkElementXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOjunkInElements(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    Object[] ok = {&amp;quot;OK&amp;quot;};&lt;br /&gt;
    Object[] obj ={dict, Arrays.asList(ok)};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(junkElementXOXO);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSpacesNewlines = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt; This item represents the main&amp;quot; +&lt;br /&gt;
      &amp;quot; point we're trying to make.&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOWithSpacesAndNewlines(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;description&amp;quot;,&amp;quot; This item represents the main&amp;quot; +&lt;br /&gt;
        &amp;quot; point we're trying to make.&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;title of item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(xoxoSpacesNewlines);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSample = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public String smartXOXOSample = &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         title=\&amp;quot;title of item 1\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         type=\&amp;quot;text/xml\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply&amp;quot; +&lt;br /&gt;
      &amp;quot; the contents of the &amp;lt;a&amp;gt; element --&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeDecoding(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object xoxoDict = parser.parse(xoxoSample);&lt;br /&gt;
      Object xoxoDict2 = parser.parse(smartXOXOSample);&lt;br /&gt;
      assertEquals(xoxoDict,xoxoDict2);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String specialAttrHTML =  &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot; title=\&amp;quot;sample url\&amp;quot; &amp;quot; +&lt;br /&gt;
      &amp;quot;rel=\&amp;quot;help\&amp;quot; type=\&amp;quot;text/xml\&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeEncode(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    assertEquals(specialAttrHTML,html);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripFull(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoText(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoTextOrTitle(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testUnicodeRoundTrip(){&lt;br /&gt;
    String s = &amp;quot;Tantek Çelik and a snowman ?&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(s);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newString = parser.parse(html);&lt;br /&gt;
      assertEquals(s,newString);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= PHP =&lt;br /&gt;
== xoxolib.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
function getKind($struct)&lt;br /&gt;
{&lt;br /&gt;
    if (!is_array($struct)) return 'string';&lt;br /&gt;
    if (!isset($struct[0]))&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    else if (array_keys($struct)==range(0,count($struct)-1))&lt;br /&gt;
        $result = 'list';&lt;br /&gt;
    else&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    return $result;&lt;br /&gt;
}&lt;br /&gt;
function makeXOXO($struct,$className='')&lt;br /&gt;
{&lt;br /&gt;
    $s='';&lt;br /&gt;
    $kind = getKind($struct);&lt;br /&gt;
    #echo &amp;quot;$kind:\n&amp;quot;;&lt;br /&gt;
    #var_dump($struct);&lt;br /&gt;
    if ($kind=='list')&lt;br /&gt;
        {&lt;br /&gt;
        if ($className)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol class=\&amp;quot;$className\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
        else &lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol&amp;gt;&amp;quot;;&lt;br /&gt;
        foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;li&amp;gt;&amp;quot; . makeXOXO($value) .&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
    else if ($kind=='dictionary')&lt;br /&gt;
        {&lt;br /&gt;
        if (isset($struct['url']))&lt;br /&gt;
            {&lt;br /&gt;
            $s .='&amp;lt;a href=&amp;quot;' .$struct['url']. '&amp;quot; ';&lt;br /&gt;
            if (isset($struct['text']))&lt;br /&gt;
                $text= $struct['text'];&lt;br /&gt;
            else if (isset($struct['title']))&lt;br /&gt;
                $text= $struct['title'];&lt;br /&gt;
            else&lt;br /&gt;
                $text= $struct['url'];&lt;br /&gt;
            foreach (array('title','rel','type') as $attr)&lt;br /&gt;
                if (isset($struct[$attr]))&lt;br /&gt;
                    {&lt;br /&gt;
                    $s .= &amp;quot;$attr=\&amp;quot;&amp;quot; . $struct[$attr] .'&amp;quot; ';&lt;br /&gt;
                    unset($struct[$attr]);&lt;br /&gt;
                    }&lt;br /&gt;
            $s .= &amp;quot;&amp;gt;&amp;quot; . makeXOXO($text) .&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
            unset($struct['url'],$struct['text']);&lt;br /&gt;
            }&lt;br /&gt;
        if (count($struct))&lt;br /&gt;
            {&lt;br /&gt;
            $s .=&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
            foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
                $s .= &amp;quot;&amp;lt;dt&amp;gt;$key&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;quot;. makeXOXO($value) . &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;;&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    else&lt;br /&gt;
        $s .= &amp;quot;$struct&amp;quot;;&lt;br /&gt;
    #echo &amp;quot;returned $s\n&amp;quot;;&lt;br /&gt;
    return $s;&lt;br /&gt;
}&lt;br /&gt;
function toXOXO($struct,$addHTMLWrapper=FALSE,$cssUrl='')&lt;br /&gt;
{&lt;br /&gt;
    if (getKind($struct) != 'list')&lt;br /&gt;
        $struct = array($struct);&lt;br /&gt;
    $xoxo = makeXOXO($struct,'xoxo');&lt;br /&gt;
    if ($addHTMLWrapper)&lt;br /&gt;
        {&lt;br /&gt;
        $s= '&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;';&lt;br /&gt;
        if ($cssUrl) $s .=&amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot; &amp;gt;@import \&amp;quot;$cssUrl\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;$xoxo&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
        return $s;&lt;br /&gt;
        }&lt;br /&gt;
    return $xoxo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function pushStruct($struct,&amp;amp;$structstack,&amp;amp;$xostack,$structType)&lt;br /&gt;
{&lt;br /&gt;
    if (is_array($struct) &amp;amp;&amp;amp; $structType=='dict' &amp;amp;&amp;amp; count($structstack) &amp;amp;&amp;amp; is_array(end($structstack)) &amp;amp;&amp;amp; isset($structstack[count($structstack)-1]['url']) &amp;amp;&amp;amp; end($structstack) != end($xostack))&lt;br /&gt;
        $xostack[] = &amp;amp;$structstack[count($structstack)-1]; # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
    else&lt;br /&gt;
        {&lt;br /&gt;
        $structstack[]=$struct;&lt;br /&gt;
        $xostack[]=&amp;amp;$structstack[count($structstack)-1];&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fromXOXO($html)&lt;br /&gt;
{&lt;br /&gt;
    $structs=array();&lt;br /&gt;
    $xostack=array();&lt;br /&gt;
    $textstack=array('');&lt;br /&gt;
    $dumpStacks=0;&lt;br /&gt;
    $p = xml_parser_create();&lt;br /&gt;
    xml_parse_into_struct($p, $html, $xoxoVals, $xoxoIndex);&lt;br /&gt;
    xml_parser_free($p);&lt;br /&gt;
&lt;br /&gt;
  if($dumpStacks)&lt;br /&gt;
        {&lt;br /&gt;
        echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
        var_dump($xoxoVals);&lt;br /&gt;
        var_dump($xoxoIndex);&lt;br /&gt;
        echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;; &lt;br /&gt;
        }&lt;br /&gt;
    $howmany = sizeof($xoxoVals);&lt;br /&gt;
    &lt;br /&gt;
    #echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    $x = $xoxoIndex['OL'];&lt;br /&gt;
    for ($x=0;$x&amp;lt;$howmany;++$x)&lt;br /&gt;
        {&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'OL' || $xoxoVals[$x]['tag'] == 'DL'|| $xoxoVals[$x]['tag'] == 'UL')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['tag'] == 'DL')&lt;br /&gt;
                $structType = 'dict';&lt;br /&gt;
            else &lt;br /&gt;
                $structType = 'list';&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'open')&lt;br /&gt;
                pushStruct(array(),$structs,$xostack,$structType);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'LI')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
               array_push($xostack[count($xostack)-1],$xoxoVals[$x]['value']);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                array_push($xostack[count($xostack)-1],array_pop($structs));&lt;br /&gt;
                }&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DT')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                array_push($textstack,$xoxoVals[$x]['value']);&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DD')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] = $xoxoVals[$x]['value'];&lt;br /&gt;
                }&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] =array_pop($structs);&lt;br /&gt;
                }&lt;br /&gt;
          if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'A')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $attrs = $xoxoVals[$x]['attributes'];&lt;br /&gt;
                $dict=array();&lt;br /&gt;
                foreach ($attrs as $key=&amp;gt; $value)&lt;br /&gt;
                    {&lt;br /&gt;
                    if ($key=='HREF')&lt;br /&gt;
                        $dict['url'] = $value;&lt;br /&gt;
                    else&lt;br /&gt;
                        $dict[strtolower($key)] = $value;&lt;br /&gt;
                    }&lt;br /&gt;
                $val = $xoxoVals[$x]['value'];&lt;br /&gt;
                if (isset($val) &amp;amp;&amp;amp; ($val != $dict['title']) &amp;amp;&amp;amp; ($val != $dict['url']))&lt;br /&gt;
                    $dict['text'] = $val;&lt;br /&gt;
                pushStruct($dict,$structs,$xostack,'dict');&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
 &lt;br /&gt;
                if($dumpStacks)&lt;br /&gt;
                    {&lt;br /&gt;
                    echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                    var_dump($structs);&lt;br /&gt;
                    var_dump($xostack);&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
     #echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;;&lt;br /&gt;
   while (count($structs) == 1 &amp;amp;&amp;amp; getKind($structs) == 'list')&lt;br /&gt;
        $structs = $structs[0];&lt;br /&gt;
    return $structs;&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== xoxotest.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
include(&amp;quot;xoxolib.php&amp;quot;);&lt;br /&gt;
function assertEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 == $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str2&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function assertArrayEqual($testname,$expected,$returned)&lt;br /&gt;
{&lt;br /&gt;
if ($expected == $returned)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($expected);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($returned);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function failIfEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 != $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;both were&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$l = array('1','2','3');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$s = 'test';&lt;br /&gt;
$html = toXOXO($s);&lt;br /&gt;
assertEqual(&amp;quot;make xoxo from a string&amp;quot;,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$htmlwrap = toXOXO($s,TRUE);&lt;br /&gt;
failIfEqual(&amp;quot;make sure wrapped and unwrapped differ&amp;quot;,html,htmlwrap);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$htmlwrap);&lt;br /&gt;
$csswrap = toXOXO($s,TRUE,&amp;quot;reaptest.css&amp;quot;);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo with css link from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$csswrap);&lt;br /&gt;
$l2 = array('1',array('2','3'));&lt;br /&gt;
$html = toXOXO($l2);&lt;br /&gt;
assertEqual('make xoxo from nested list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from 1-element dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','thing'=&amp;gt;'and another thing...');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and thing','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;thing&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;and another thing...&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','list'=&amp;gt;array('and', 'another','thing...'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;list&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;and&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;another&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;thing...&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from dict in list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;a&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;2&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$l = array('3','2','1');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list to xoxo and back',$l,$newdl);&lt;br /&gt;
$l = array('1',array('a','b'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
&lt;br /&gt;
$l= array('3',array('a','2'),array('b',array('1',array('c','4'))));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'),array('b'=&amp;gt;'1','c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('list of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'two'=&amp;gt;array('c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'url'=&amp;gt;'http://example.com');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts with url to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts with url to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$d = array('test'=&amp;gt; array('1','2'),&lt;br /&gt;
'name'=&amp;gt; 'Kevin','nestlist'=&amp;gt; array('a',array('b','c')),&lt;br /&gt;
'nestdict'=&amp;gt;array('e'=&amp;gt;'6','f'=&amp;gt;'7'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary of lists  to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$d=fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text outside &amp;amp;lt;li&amp;amp;gt; etc is ignored',array(good=&amp;gt;buy),$d);&lt;br /&gt;
&lt;br /&gt;
$l=fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text within &amp;amp;lt;li&amp;amp;gt; but outside a subcontainer is ignored',array(array(good=&amp;gt;buy),array('OK')),$l);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$d2=array('text'=&amp;gt;'item 1',&lt;br /&gt;
    'description'=&amp;gt;&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
    'url'=&amp;gt;'http://example.com/more.xoxo',&lt;br /&gt;
    'title'=&amp;gt;'title of item 1',&lt;br /&gt;
    'type'=&amp;gt;'text/xml',&lt;br /&gt;
    'rel'=&amp;gt;'help');&lt;br /&gt;
assertArrayEqual('unmung some xoxo with spaces in and check result is right',$d2,$d);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (no text)',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (just url)',$d,fromXOXO($html));&lt;br /&gt;
$kmattn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
$d=fromXOXO($kmattn);&lt;br /&gt;
$newattn = toXOXO($d);&lt;br /&gt;
$d2=fromXOXO($newattn);&lt;br /&gt;
assertArrayEqual('attention double round-trip',$d,$d2);&lt;br /&gt;
assertEqual('attention triple round-trip',$newattn,toXOXO($d2));&lt;br /&gt;
assertEqual('attention one round-trip',$kmattn,$newattn);&lt;br /&gt;
$d=array(array(url=&amp;gt;&amp;quot;http://www.boingboing.net/&amp;quot;,title=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://boingboing.net/rss.xml&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;),array(url=&amp;gt;&amp;quot;http://www.financialcryptography.com/&amp;quot;,title=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;));&lt;br /&gt;
$attn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
assertEqual('attention encode',$attn,toXOXO($d));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
== autres implémentations ==&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/xoxo2array.php.txt xoxo2array.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/array2xoxo.php.txt array2xoxo.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/#outlineclasses Outline Classes]&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-python&amp;diff=43013</id>
		<title>xoxo-sample-code-python</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-python&amp;diff=43013"/>
		<updated>2010-08-29T18:09:37Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Sample Code - Python=&lt;br /&gt;
:'''this is  sub-page of [[xoxo-sample-code]]'''&lt;br /&gt;
&lt;br /&gt;
== xoxo.py ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;xoxo.py - a utility module for transforming to and from the XHTMLOutlines format XOXO http://microformats.org/wiki/xoxo&lt;br /&gt;
toXOXO takes a Python datastructure (tuples, lists or dictionaries, arbitrarily nested) and returns a XOXO representation of it.&lt;br /&gt;
fromXOXO parses an XHTML file for a xoxo list and returns the structure&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__version__ = &amp;quot;0.9&amp;quot;&lt;br /&gt;
__date__ = &amp;quot;2005-11-02&amp;quot;&lt;br /&gt;
__author__ = &amp;quot;Kevin Marks &amp;lt;kmarks@technorati.com&amp;gt;&amp;quot;&lt;br /&gt;
__copyright__ = &amp;quot;Copyright 2004-2006, Kevin Marks &amp;amp; Technorati&amp;quot;&lt;br /&gt;
__license__ = &amp;quot;http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0&amp;quot;&lt;br /&gt;
__credits__ = &amp;quot;&amp;quot;&amp;quot;Tantek Çelik and Mark Pilgrim for data structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__history__ = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
TODO: add &amp;lt;title&amp;gt; tag&lt;br /&gt;
TODO: add a proper profile link&lt;br /&gt;
0.9 smarter parsing for encoding and partial markup; fix dangling dictionary case&lt;br /&gt;
0.8 work in unicode then render to utf-8&lt;br /&gt;
0.7 initial encoding support - just utf-8 for now&lt;br /&gt;
0.6 support the special behavior for url properties  to/from &amp;lt;a&amp;gt;&lt;br /&gt;
0.5 fix some awkward side effects of whitespace and text outside our expected tags; simplify writing code&lt;br /&gt;
0.4 add correct XHTML headers so it validates&lt;br /&gt;
0.3 read/write version; fixed invalid nested list generation;&lt;br /&gt;
0.1 first write-only version&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    True, False&lt;br /&gt;
except NameError:&lt;br /&gt;
    True, False = not not 1, not 1&lt;br /&gt;
containerTags={'ol':False,'ul':False,'dl':False}&lt;br /&gt;
import sgmllib, urllib, urlparse, re,codecs&lt;br /&gt;
&lt;br /&gt;
def toUnicode(key):&lt;br /&gt;
    if type(key) == type(u'unicode'):&lt;br /&gt;
        uKey= key&lt;br /&gt;
    else:&lt;br /&gt;
        try: &lt;br /&gt;
            uKey=unicode(key,'utf-8')&lt;br /&gt;
        except:&lt;br /&gt;
            uKey=unicode(key,'windows_1252')&lt;br /&gt;
    return uKey&lt;br /&gt;
&lt;br /&gt;
def makeXOXO(struct,className=None):&lt;br /&gt;
    s=u''&lt;br /&gt;
    if isinstance(struct,(list,tuple)):&lt;br /&gt;
        if className:&lt;br /&gt;
            s += u'&amp;lt;ol class=&amp;quot;%s&amp;quot;&amp;gt;' % className&lt;br /&gt;
        else:&lt;br /&gt;
            s+= u&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;&lt;br /&gt;
        for item in struct:&lt;br /&gt;
            s+=u&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,None)+&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
        s +=u&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;br /&gt;
    elif isinstance(struct,dict):&lt;br /&gt;
        d=struct.copy()&lt;br /&gt;
        if 'url' in d:&lt;br /&gt;
            uURL=toUnicode(d['url'])&lt;br /&gt;
            s+=u'&amp;lt;a href=&amp;quot;%s&amp;quot; ' % uURL&lt;br /&gt;
            text =  d.get('text',d.get('title',uURL))&lt;br /&gt;
            for attr in ('title','rel','type'):&lt;br /&gt;
                if attr in d:&lt;br /&gt;
                    xVal = makeXOXO(d[attr],None)&lt;br /&gt;
                    s +=u'%s=&amp;quot;%s&amp;quot; ' % (attr,xVal)&lt;br /&gt;
                    del d[attr]&lt;br /&gt;
            s +=u'&amp;gt;%s&amp;lt;/a&amp;gt;' % makeXOXO(text,None)&lt;br /&gt;
            if 'text' in d:&lt;br /&gt;
                del d['text']&lt;br /&gt;
            del d['url']&lt;br /&gt;
        if len(d):&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;&lt;br /&gt;
            for key,value in d.items():&lt;br /&gt;
                xVal = makeXOXO(value,None)&lt;br /&gt;
                uKey=toUnicode(key)&lt;br /&gt;
                s+= u'&amp;lt;dt&amp;gt;%s&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;%s&amp;lt;/dd&amp;gt;' % (uKey, xVal)&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
    elif type(struct) == type(u'unicode'):&lt;br /&gt;
        s+=struct&lt;br /&gt;
    else:&lt;br /&gt;
        if type(struct)!=type(' '):&lt;br /&gt;
            struct=str(struct)&lt;br /&gt;
        s += toUnicode(struct)&lt;br /&gt;
    return s&lt;br /&gt;
class AttrParser(sgmllib.SGMLParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        sgmllib.SGMLParser.__init__(self)&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.encoding='utf-8'&lt;br /&gt;
    def cleanText(self,inText):&lt;br /&gt;
        if type(inText) == type(u'unicode'):&lt;br /&gt;
            inText = inText.encode(self.encoding,'replace')&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.reset()&lt;br /&gt;
        self.feed(inText)&lt;br /&gt;
        return ''.join(self.text)&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        if 'ascii' in encoding:&lt;br /&gt;
            encoding='windows_1252' # so we don't throw an exception on high-bit set chars in there by mistake&lt;br /&gt;
        if encoding and encoding !='text/html':&lt;br /&gt;
            try:&lt;br /&gt;
                canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                self.encoding = encoding&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    encoding='japanese.' +encoding&lt;br /&gt;
                    canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                    self.encoding = encoding&lt;br /&gt;
                except:&lt;br /&gt;
                    print &amp;quot;can't deal with encoding %s&amp;quot; % encoding&lt;br /&gt;
                    &lt;br /&gt;
    def handle_entityref(self, ref):&lt;br /&gt;
        # called for each entity reference, e.g. for &amp;quot;&amp;amp;copy;&amp;quot;, ref will be &amp;quot;copy&amp;quot;&lt;br /&gt;
        # map through to unicode where we can&lt;br /&gt;
        try:&lt;br /&gt;
            entity =htmlentitydefs.name2codepoint[ref]&lt;br /&gt;
            self.handleUnicodeData(unichr(entity))&lt;br /&gt;
        except:&lt;br /&gt;
            try:&lt;br /&gt;
                handle_charref(ref) # deal with char-ref's missing the '#' (see Akma)&lt;br /&gt;
            except:&lt;br /&gt;
                self.handle_data(&amp;quot;&amp;amp;%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
    def handle_charref(self, ref):&lt;br /&gt;
        # called for each character reference, e.g. for &amp;quot;&amp;amp;#160;&amp;quot;, ref will be &amp;quot;160&amp;quot;&lt;br /&gt;
        # Reconstruct the original character reference.&lt;br /&gt;
        try:&lt;br /&gt;
            if ref[0]=='x':&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref[1:],16)))&lt;br /&gt;
            else:&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref)))&lt;br /&gt;
        except:&lt;br /&gt;
            self.handle_data(&amp;quot;&amp;amp;#%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
# called for each block of plain text, i.e. outside of any tag and&lt;br /&gt;
# not containing any character or entity references&lt;br /&gt;
    def handle_data(self, text):&lt;br /&gt;
        if type(text)==type(u' '):&lt;br /&gt;
            self.handleUnicodeData(text)&lt;br /&gt;
        if self.encoding== 'utf-8':&lt;br /&gt;
            try:&lt;br /&gt;
                uText = unicode(text,self.encoding) #utf-8 is pretty clear when it is wrong&lt;br /&gt;
            except:&lt;br /&gt;
                uText = unicode(text,'windows_1252','ignore') # and this is the likely wrongness&lt;br /&gt;
        else:&lt;br /&gt;
            uText = unicode(text,self.encoding,'replace') # if they have really broken encoding, (eg lots of shift-JIS blogs)&lt;br /&gt;
        self.handleUnicodeData(uText)&lt;br /&gt;
    def handleUnicodeData(self, uText):&lt;br /&gt;
        self.text.append(uText)&lt;br /&gt;
        &lt;br /&gt;
class xoxoParser(AttrParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        AttrParser.__init__(self)&lt;br /&gt;
        self.structs=[]&lt;br /&gt;
        self.xostack=[]&lt;br /&gt;
        self.textstack=['']&lt;br /&gt;
        self.attrparse = AttrParser()&lt;br /&gt;
    def normalize_attrs(self, attrs):&lt;br /&gt;
        attrs = [(k.lower(), self.attrparse.cleanText(v)) for k, v in attrs]&lt;br /&gt;
        attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs]&lt;br /&gt;
        return attrs&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        AttrParser.setEncoding(self,encoding)&lt;br /&gt;
        self.attrparse.setEncoding(encoding)&lt;br /&gt;
    def pushStruct(self,struct):&lt;br /&gt;
        if type(struct) == type({}) and len(struct)==0 and len(self.structs) and type(self.structs[-1]) == type({}) and 'url' in self.structs[-1] and self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            self.xostack.append(self.structs[-1]) # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
        else:&lt;br /&gt;
            self.structs.append(struct)&lt;br /&gt;
            self.xostack.append(self.structs[-1])&lt;br /&gt;
    def do_meta(self, attributes):&lt;br /&gt;
        atts = dict(self.normalize_attrs(attributes))&lt;br /&gt;
        #print atts.encode('utf-8')&lt;br /&gt;
        if 'http-equiv' in atts:&lt;br /&gt;
            if atts['http-equiv'].lower() == &amp;quot;content-type&amp;quot;:&lt;br /&gt;
                if 'content' in atts:&lt;br /&gt;
                    encoding = atts['content'].split('charset=')[-1]&lt;br /&gt;
                    self.setEncoding(encoding)&lt;br /&gt;
    def start_a(self,attrs):&lt;br /&gt;
        attrsD = dict(self.normalize_attrs(attrs))&lt;br /&gt;
        attrsD['url']= attrsD.get('href','')&lt;br /&gt;
        if 'href' in attrsD:&lt;br /&gt;
            del attrsD['href']&lt;br /&gt;
        self.pushStruct(attrsD)&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_a(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        if val: &lt;br /&gt;
            if self.xostack[-1].get('title','') == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if self.xostack[-1]['url'] == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if val:&lt;br /&gt;
                self.xostack[-1]['text']=val&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_dl(self,attrs):&lt;br /&gt;
        self.pushStruct({})&lt;br /&gt;
    def end_dl(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ol(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ol(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ul(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ul(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_li(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_li(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        while self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
        if type(val) == type(' ') or type(val) == type(u' '):&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
    def start_dt(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dt(self):&lt;br /&gt;
        pass&lt;br /&gt;
    def start_dd(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dd(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        key = self.textstack.pop()&lt;br /&gt;
        if self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
        self.xostack[-1][key]=val&lt;br /&gt;
    def handleUnicodeData(self, text):&lt;br /&gt;
        if len(self.stack) and containerTags.get(self.stack[-1],True): #skip text not within an element&lt;br /&gt;
            self.textstack[-1] += text&lt;br /&gt;
def toXOXO(struct,addHTMLWrapper=False,cssUrl=''):&lt;br /&gt;
    if type(struct) ==type((1,))or type(struct) ==type([1,]):&lt;br /&gt;
        inStruct = struct&lt;br /&gt;
    else:&lt;br /&gt;
        inStruct = [struct]&lt;br /&gt;
    if addHTMLWrapper:&lt;br /&gt;
        s= u'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;'''&lt;br /&gt;
        if cssUrl:&lt;br /&gt;
            s+=u'&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;%s&amp;quot;;&amp;lt;/style&amp;gt;' % cssUrl&lt;br /&gt;
        s+=u&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot; % makeXOXO(inStruct,'xoxo')&lt;br /&gt;
        return s.encode('utf-8')&lt;br /&gt;
    else:&lt;br /&gt;
        return makeXOXO(inStruct,'xoxo').encode('utf-8')&lt;br /&gt;
    &lt;br /&gt;
def fromXOXO(html):&lt;br /&gt;
    parser = xoxoParser()&lt;br /&gt;
    #parser.feed(unicode(html,'utf-8'))&lt;br /&gt;
    parser.feed(html)&lt;br /&gt;
    #print parser.structs&lt;br /&gt;
    structs=[struct for struct in parser.structs if struct]&lt;br /&gt;
    #print structs&lt;br /&gt;
    while len(structs) ==1 and type(structs)==type([1,]):&lt;br /&gt;
        structs=structs[0]&lt;br /&gt;
    return structs&lt;br /&gt;
&lt;br /&gt;
# Allow direct invocation&lt;br /&gt;
# Read HTML from URL, parse into data structures, then re-output&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  if len(sys.argv) &amp;lt; 2: raise SystemExit(&amp;quot;Usage: &amp;quot;+sys.argv[0]+&amp;quot; url\n&amp;quot;+__doc__)&lt;br /&gt;
  url=sys.argv[1]&lt;br /&gt;
  file = urllib.urlopen(url)&lt;br /&gt;
  html=file.read(-1)&lt;br /&gt;
  file.close&lt;br /&gt;
  s=fromXOXO(html)&lt;br /&gt;
  p=toXOXO(s,True)&lt;br /&gt;
  print p&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== testxoxo.py  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;testxoxo.py &lt;br /&gt;
Unit tests for xoxo.py&lt;br /&gt;
This file tests the functions in xoxo.py &lt;br /&gt;
The underlying model here is http://diveintopython.org/unit_testing/index.html &lt;br /&gt;
&lt;br /&gt;
run from command line with&lt;br /&gt;
python testxoxo.py -v&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import xoxo&lt;br /&gt;
reload(xoxo)&lt;br /&gt;
import unittest&lt;br /&gt;
&lt;br /&gt;
class xoxoTestCases(unittest.TestCase):&lt;br /&gt;
    &lt;br /&gt;
    def testSimpleList(self):&lt;br /&gt;
        '''make a xoxo file from a list'''&lt;br /&gt;
        l = ['1','2','3']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
    def testNestedList(self):&lt;br /&gt;
        '''make a xoxo file from a list with a list in'''&lt;br /&gt;
        l = ['1',['2','3']]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testDictionary(self):&lt;br /&gt;
        '''make a xoxo file from a dictionary'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testSingleItem(self):&lt;br /&gt;
        '''make a xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testWrapDiffers(self):&lt;br /&gt;
        '''make a xoxo file from a string with and without html wrapper and check they are different'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        htmlwrap =  xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.failIfEqual(html,htmlwrap)&lt;br /&gt;
&lt;br /&gt;
    def testWrapSingleItem(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testWrapItemWithCSS(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True,cssUrl='reaptest.css')&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
        &lt;br /&gt;
    def testDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary wiht an url in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)    &lt;br /&gt;
    def testNestedDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with a dict in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionariesWithURLsRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict with an url into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin','url':'http://slashdot.org'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testListRoundTrip(self):&lt;br /&gt;
        ''' make a list into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3','2','1']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofDictsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Dicts into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',{'a':'2'},{'b':'1','c':'4'}]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofListsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Lists into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',['a','2'],['b',['1',['c','4']]]]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testDictofListsRoundTrip(self):&lt;br /&gt;
        ''' make a dict with lists in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':['1','2'],&lt;br /&gt;
        'name':'Kevin',&lt;br /&gt;
        'nestlist':['a',['b','c']],&lt;br /&gt;
        'nestdict':{'e':'6','f':'7'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInContainers(self):&lt;br /&gt;
        '''make sure text outside &amp;lt;li&amp;gt; etc is ignored'''&lt;br /&gt;
        d=xoxo.fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(d,{'good': 'buy'})&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInElements(self):&lt;br /&gt;
        '''make sure text within &amp;lt;li&amp;gt; but outside a subcontainer is ignored'''&lt;br /&gt;
        l=xoxo.fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(l,[{'good': 'buy'},['OK']])&lt;br /&gt;
&lt;br /&gt;
    def testXOXOWithSpacesAndNewlines(self):&lt;br /&gt;
        '''unmung some xoxo with spaces in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        d2={'text':'item 1',&lt;br /&gt;
            'description':&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
            'url':'http://example.com/more.xoxo',&lt;br /&gt;
            'title':'title of item 1',&lt;br /&gt;
            'type':'text/xml',&lt;br /&gt;
            'rel':'help'&lt;br /&gt;
            }&lt;br /&gt;
        xoxoAgain = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        #this needs a smarter whitespace-sensitive comparison&lt;br /&gt;
        #self.assertEqual(xoxoSample,xoxoAgain)&lt;br /&gt;
&lt;br /&gt;
    def testSpecialAttributeDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeAndDLDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in plus a &amp;lt;dl&amp;gt; in the same item and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeEncode(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        expectedHTML= '&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;' &lt;br /&gt;
        self.assertEqual(html,expectedHTML)&lt;br /&gt;
        &lt;br /&gt;
    def testSpecialAttributeRoundTripFull(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoText(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoTextOrTitle(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text or title attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testAttentionRoundTrip(self):&lt;br /&gt;
        '''check nested &amp;lt;a&amp;gt; and &amp;lt;dl&amp;gt; and &amp;lt;a&amp;gt; are preserved'''&lt;br /&gt;
        kmattn='''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;''';&lt;br /&gt;
        d = xoxo.fromXOXO(kmattn)&lt;br /&gt;
        newattn = xoxo.toXOXO(d)&lt;br /&gt;
        d2 = xoxo.fromXOXO(newattn)&lt;br /&gt;
        self.assertEqual(newattn,xoxo.toXOXO(d2))&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        self.assertEqual(kmattn,newattn)&lt;br /&gt;
        &lt;br /&gt;
    def testUnicodeRoundtrip(self):&lt;br /&gt;
        '''check unicode characters can go to xoxo and back'''&lt;br /&gt;
        src=unicode('Tantek \xc3\x87elik and a snowman \xe2\x98\x83','utf-8')&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html))&lt;br /&gt;
    def testUtf8Roundtrip(self):&lt;br /&gt;
        '''check utf8 characters can go to xoxo and back'''&lt;br /&gt;
        src='Tantek \xc3\x87elik and a snowman \xe2\x98\x83'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('utf-8'))&lt;br /&gt;
    def testWindows1252Roundtrip(self):&lt;br /&gt;
        '''check 1252 characters can go to xoxo and back'''&lt;br /&gt;
        src='This is an evil\xa0space'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('windows-1252'))&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    unittest.main()&lt;br /&gt;
else:&lt;br /&gt;
    runner = unittest.TextTestRunner()&lt;br /&gt;
    suite = unittest.makeSuite(xoxoTestCases,'test')&lt;br /&gt;
    runner.run(suite)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=41708</id>
		<title>xoxo-sample-code-fr</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=41708"/>
		<updated>2010-01-27T18:30:35Z</updated>

		<summary type="html">&lt;p&gt;Newacct: /* XOXOParser.java */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Code Echantillon =&lt;br /&gt;
&lt;br /&gt;
Un paquet général de code échantillon open source, ([http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0]) pour lire et écrire des fichiers [[xoxo-fr|xoxo]] en Python et Java (avec Perl, PHP, ... à suivre).&lt;br /&gt;
= Python =&lt;br /&gt;
== xoxo.py ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;xoxo.py - a utility module for transforming to and from the XHTMLOutlines format XOXO http://microformats.org/wiki/xoxo&lt;br /&gt;
toXOXO takes a Python datastructure (tuples, lists or dictionaries, arbitrarily nested) and returns a XOXO representation of it.&lt;br /&gt;
fromXOXO parses an XHTML file for a xoxo list and returns the structure&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__version__ = &amp;quot;0.9&amp;quot;&lt;br /&gt;
__date__ = &amp;quot;2005-11-02&amp;quot;&lt;br /&gt;
__author__ = &amp;quot;Kevin Marks &amp;lt;kmarks@technorati.com&amp;gt;&amp;quot;&lt;br /&gt;
__copyright__ = &amp;quot;Copyright 2004-2006, Kevin Marks &amp;amp; Technorati&amp;quot;&lt;br /&gt;
__license__ = &amp;quot;http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0&amp;quot;&lt;br /&gt;
__credits__ = &amp;quot;&amp;quot;&amp;quot;Tantek Çelik and Mark Pilgrim for data structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__history__ = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
TODO: add &amp;lt;title&amp;gt; tag&lt;br /&gt;
TODO: add a proper profile link&lt;br /&gt;
0.9 smarter parsing for encoding and partial markup; fix dangling dictionary case&lt;br /&gt;
0.8 work in unicode then render to utf-8&lt;br /&gt;
0.7 initial encoding support - just utf-8 for now&lt;br /&gt;
0.6 support the special behavior for url properties  to/from &amp;lt;a&amp;gt;&lt;br /&gt;
0.5 fix some awkward side effects of whitespace and text outside our expected tags; simplify writing code&lt;br /&gt;
0.4 add correct XHTML headers so it validates&lt;br /&gt;
0.3 read/write version; fixed invalid nested list generation;&lt;br /&gt;
0.1 first write-only version&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    True, False&lt;br /&gt;
except NameError:&lt;br /&gt;
    True, False = not not 1, not 1&lt;br /&gt;
containerTags={'ol':False,'ul':False,'dl':False}&lt;br /&gt;
import sgmllib, urllib, urlparse, re,codecs&lt;br /&gt;
&lt;br /&gt;
def toUnicode(key):&lt;br /&gt;
    if type(key) == type(u'unicode'):&lt;br /&gt;
        uKey= key&lt;br /&gt;
    else:&lt;br /&gt;
        try: &lt;br /&gt;
            uKey=unicode(key,'utf-8')&lt;br /&gt;
        except:&lt;br /&gt;
            uKey=unicode(key,'windows_1252')&lt;br /&gt;
    return uKey&lt;br /&gt;
&lt;br /&gt;
def makeXOXO(struct,className=None):&lt;br /&gt;
    s=u''&lt;br /&gt;
    if isinstance(struct,list) or isinstance(struct,tuple):&lt;br /&gt;
        if className:&lt;br /&gt;
            s += u'&amp;lt;ol class=&amp;quot;%s&amp;quot;&amp;gt;' % className&lt;br /&gt;
        else:&lt;br /&gt;
            s+= u&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;&lt;br /&gt;
        for item in struct:&lt;br /&gt;
            s+=u&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,None)+&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
        s +=u&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;br /&gt;
    elif isinstance(struct,dict):&lt;br /&gt;
        d=struct.copy()&lt;br /&gt;
        if 'url' in d:&lt;br /&gt;
            uURL=toUnicode(d['url'])&lt;br /&gt;
            s+=u'&amp;lt;a href=&amp;quot;%s&amp;quot; ' % uURL&lt;br /&gt;
            text =  d.get('text',d.get('title',uURL))&lt;br /&gt;
            for attr in ('title','rel','type'):&lt;br /&gt;
                if attr in d:&lt;br /&gt;
                    xVal = makeXOXO(d[attr],None)&lt;br /&gt;
                    s +=u'%s=&amp;quot;%s&amp;quot; ' % (attr,xVal)&lt;br /&gt;
                    del d[attr]&lt;br /&gt;
            s +=u'&amp;gt;%s&amp;lt;/a&amp;gt;' % makeXOXO(text,None)&lt;br /&gt;
            if 'text' in d:&lt;br /&gt;
                del d['text']&lt;br /&gt;
            del d['url']&lt;br /&gt;
        if len(d):&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;&lt;br /&gt;
            for key,value in d.items():&lt;br /&gt;
                xVal = makeXOXO(value,None)&lt;br /&gt;
                uKey=toUnicode(key)&lt;br /&gt;
                s+= u'&amp;lt;dt&amp;gt;%s&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;%s&amp;lt;/dd&amp;gt;' % (uKey, xVal)&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
    elif type(struct) == type(u'unicode'):&lt;br /&gt;
        s+=struct&lt;br /&gt;
    else:&lt;br /&gt;
        if type(struct)!=type(' '):&lt;br /&gt;
            struct=str(struct)&lt;br /&gt;
        s += toUnicode(struct)&lt;br /&gt;
    return s&lt;br /&gt;
class AttrParser(sgmllib.SGMLParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        sgmllib.SGMLParser.__init__(self)&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.encoding='utf-8'&lt;br /&gt;
    def cleanText(self,inText):&lt;br /&gt;
        if type(inText) == type(u'unicode'):&lt;br /&gt;
            inText = inText.encode(self.encoding,'replace')&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.reset()&lt;br /&gt;
        self.feed(inText)&lt;br /&gt;
        return ''.join(self.text)&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        if 'ascii' in encoding:&lt;br /&gt;
            encoding='windows_1252' # so we don't throw an exception on high-bit set chars in there by mistake&lt;br /&gt;
        if encoding and not encoding =='text/html':&lt;br /&gt;
            try:&lt;br /&gt;
                canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                self.encoding = encoding&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    encoding='japanese.' +encoding&lt;br /&gt;
                    canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                    self.encoding = encoding&lt;br /&gt;
                except:&lt;br /&gt;
                    print &amp;quot;can't deal with encoding %s&amp;quot; % encoding&lt;br /&gt;
                    &lt;br /&gt;
    def handle_entityref(self, ref):&lt;br /&gt;
        # called for each entity reference, e.g. for &amp;quot;&amp;amp;copy;&amp;quot;, ref will be &amp;quot;copy&amp;quot;&lt;br /&gt;
        # map through to unicode where we can&lt;br /&gt;
        try:&lt;br /&gt;
            entity =htmlentitydefs.name2codepoint[ref]&lt;br /&gt;
            self.handleUnicodeData(unichr(entity))&lt;br /&gt;
        except:&lt;br /&gt;
            try:&lt;br /&gt;
                handle_charref(ref) # deal with char-ref's missing the '#' (see Akma)&lt;br /&gt;
            except:&lt;br /&gt;
                self.handle_data(&amp;quot;&amp;amp;%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
    def handle_charref(self, ref):&lt;br /&gt;
        # called for each character reference, e.g. for &amp;quot;&amp;amp;#160;&amp;quot;, ref will be &amp;quot;160&amp;quot;&lt;br /&gt;
        # Reconstruct the original character reference.&lt;br /&gt;
        try:&lt;br /&gt;
            if ref[0]=='x':&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref[1:],16)))&lt;br /&gt;
            else:&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref)))&lt;br /&gt;
        except:&lt;br /&gt;
            self.handle_data(&amp;quot;&amp;amp;#%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
# called for each block of plain text, i.e. outside of any tag and&lt;br /&gt;
# not containing any character or entity references&lt;br /&gt;
    def handle_data(self, text):&lt;br /&gt;
        if type(text)==type(u' '):&lt;br /&gt;
            self.handleUnicodeData(text)&lt;br /&gt;
        if self.encoding== 'utf-8':&lt;br /&gt;
            try:&lt;br /&gt;
                uText = unicode(text,self.encoding) #utf-8 is pretty clear when it is wrong&lt;br /&gt;
            except:&lt;br /&gt;
                uText = unicode(text,'windows_1252','ignore') # and this is the likely wrongness&lt;br /&gt;
        else:&lt;br /&gt;
            uText = unicode(text,self.encoding,'replace') # if they have really broken encoding, (eg lots of shift-JIS blogs)&lt;br /&gt;
        self.handleUnicodeData(uText)&lt;br /&gt;
    def handleUnicodeData(self, uText):&lt;br /&gt;
        self.text.append(uText)&lt;br /&gt;
        &lt;br /&gt;
class xoxoParser(AttrParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        AttrParser.__init__(self)&lt;br /&gt;
        self.structs=[]&lt;br /&gt;
        self.xostack=[]&lt;br /&gt;
        self.textstack=['']&lt;br /&gt;
        self.attrparse = AttrParser()&lt;br /&gt;
    def normalize_attrs(self, attrs):&lt;br /&gt;
        attrs = [(k.lower(), self.attrparse.cleanText(v)) for k, v in attrs]&lt;br /&gt;
        attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs]&lt;br /&gt;
        return attrs&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        AttrParser.setEncoding(self,encoding)&lt;br /&gt;
        self.attrparse.setEncoding(encoding)&lt;br /&gt;
    def pushStruct(self,struct):&lt;br /&gt;
        if type(struct) == type({}) and len(struct)==0 and len(self.structs) and type(self.structs[-1]) == type({}) and 'url' in self.structs[-1] and self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            self.xostack.append(self.structs[-1]) # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
        else:&lt;br /&gt;
            self.structs.append(struct)&lt;br /&gt;
            self.xostack.append(self.structs[-1])&lt;br /&gt;
    def do_meta(self, attributes):&lt;br /&gt;
        atts = dict(self.normalize_attrs(attributes))&lt;br /&gt;
        #print atts.encode('utf-8')&lt;br /&gt;
        if 'http-equiv' in atts:&lt;br /&gt;
            if atts['http-equiv'].lower() == &amp;quot;content-type&amp;quot;:&lt;br /&gt;
                if 'content' in atts:&lt;br /&gt;
                    encoding = atts['content'].split('charset=')[-1]&lt;br /&gt;
                    self.setEncoding(encoding)&lt;br /&gt;
    def start_a(self,attrs):&lt;br /&gt;
        attrsD = dict(self.normalize_attrs(attrs))&lt;br /&gt;
        attrsD['url']= attrsD.get('href','')&lt;br /&gt;
        if 'href' in attrsD:&lt;br /&gt;
            del attrsD['href']&lt;br /&gt;
        self.pushStruct(attrsD)&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_a(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        if val: &lt;br /&gt;
            if self.xostack[-1].get('title','') == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if self.xostack[-1]['url'] == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if val:&lt;br /&gt;
                self.xostack[-1]['text']=val&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_dl(self,attrs):&lt;br /&gt;
        self.pushStruct({})&lt;br /&gt;
    def end_dl(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ol(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ol(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ul(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ul(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_li(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_li(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        while self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
        if type(val) == type(' ') or type(val) == type(u' '):&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
    def start_dt(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dt(self):&lt;br /&gt;
        pass&lt;br /&gt;
    def start_dd(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dd(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        key = self.textstack.pop()&lt;br /&gt;
        if self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
        self.xostack[-1][key]=val&lt;br /&gt;
    def handleUnicodeData(self, text):&lt;br /&gt;
        if len(self.stack) and containerTags.get(self.stack[-1],True): #skip text not within an element&lt;br /&gt;
            self.textstack[-1] += text&lt;br /&gt;
def toXOXO(struct,addHTMLWrapper=False,cssUrl=''):&lt;br /&gt;
    if type(struct) ==type((1,))or type(struct) ==type([1,]):&lt;br /&gt;
        inStruct = struct&lt;br /&gt;
    else:&lt;br /&gt;
        inStruct = [struct]&lt;br /&gt;
    if addHTMLWrapper:&lt;br /&gt;
        s= u'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;'''&lt;br /&gt;
        if cssUrl:&lt;br /&gt;
            s+=u'&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;%s&amp;quot;;&amp;lt;/style&amp;gt;' % cssUrl&lt;br /&gt;
        s+=u&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot; % makeXOXO(inStruct,'xoxo')&lt;br /&gt;
        return s.encode('utf-8')&lt;br /&gt;
    else:&lt;br /&gt;
        return makeXOXO(inStruct,'xoxo').encode('utf-8')&lt;br /&gt;
    &lt;br /&gt;
def fromXOXO(html):&lt;br /&gt;
    parser = xoxoParser()&lt;br /&gt;
    #parser.feed(unicode(html,'utf-8'))&lt;br /&gt;
    parser.feed(html)&lt;br /&gt;
    #print parser.structs&lt;br /&gt;
    structs=[struct for struct in parser.structs if struct]&lt;br /&gt;
    #print structs&lt;br /&gt;
    while len(structs) ==1 and type(structs)==type([1,]):&lt;br /&gt;
        structs=structs[0]&lt;br /&gt;
    return structs&lt;br /&gt;
&lt;br /&gt;
# Allow direct invocation&lt;br /&gt;
# Read HTML from URL, parse into data structures, then re-output&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  if len(sys.argv) &amp;lt; 2: raise SystemExit(&amp;quot;Usage: &amp;quot;+sys.argv[0]+&amp;quot; url\n&amp;quot;+__doc__)&lt;br /&gt;
  url=sys.argv[1]&lt;br /&gt;
  file = urllib.urlopen(url)&lt;br /&gt;
  html=file.read(-1)&lt;br /&gt;
  file.close&lt;br /&gt;
  s=fromXOXO(html)&lt;br /&gt;
  p=toXOXO(s,True)&lt;br /&gt;
  print p&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== testxoxo.py  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;testxoxo.py &lt;br /&gt;
Unit tests for xoxo.py&lt;br /&gt;
This file tests the functions in xoxo.py &lt;br /&gt;
The underlying model here is http://diveintopython.org/unit_testing/index.html &lt;br /&gt;
&lt;br /&gt;
run from command line with&lt;br /&gt;
python testxoxo.py -v&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import xoxo&lt;br /&gt;
reload(xoxo)&lt;br /&gt;
import unittest&lt;br /&gt;
&lt;br /&gt;
class xoxoTestCases(unittest.TestCase):&lt;br /&gt;
    &lt;br /&gt;
    def testSimpleList(self):&lt;br /&gt;
        '''make a xoxo file from a list'''&lt;br /&gt;
        l = ['1','2','3']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
    def testNestedList(self):&lt;br /&gt;
        '''make a xoxo file from a list with a list in'''&lt;br /&gt;
        l = ['1',['2','3']]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testDictionary(self):&lt;br /&gt;
        '''make a xoxo file from a dictionary'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testSingleItem(self):&lt;br /&gt;
        '''make a xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testWrapDiffers(self):&lt;br /&gt;
        '''make a xoxo file from a string with and without html wrapper and check they are different'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        htmlwrap =  xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.failIfEqual(html,htmlwrap)&lt;br /&gt;
&lt;br /&gt;
    def testWrapSingleItem(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testWrapItemWithCSS(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True,cssUrl='reaptest.css')&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
        &lt;br /&gt;
    def testDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary wiht an url in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)    &lt;br /&gt;
    def testNestedDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with a dict in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionariesWithURLsRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict with an url into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin','url':'http://slashdot.org'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testListRoundTrip(self):&lt;br /&gt;
        ''' make a list into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3','2','1']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofDictsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Dicts into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',{'a':'2'},{'b':'1','c':'4'}]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofListsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Lists into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',['a','2'],['b',['1',['c','4']]]]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testDictofListsRoundTrip(self):&lt;br /&gt;
        ''' make a dict with lists in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':['1','2'],&lt;br /&gt;
        'name':'Kevin',&lt;br /&gt;
        'nestlist':['a',['b','c']],&lt;br /&gt;
        'nestdict':{'e':'6','f':'7'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInContainers(self):&lt;br /&gt;
        '''make sure text outside &amp;lt;li&amp;gt; etc is ignored'''&lt;br /&gt;
        d=xoxo.fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(d,{'good': 'buy'})&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInElements(self):&lt;br /&gt;
        '''make sure text within &amp;lt;li&amp;gt; but outside a subcontainer is ignored'''&lt;br /&gt;
        l=xoxo.fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(l,[{'good': 'buy'},['OK']])&lt;br /&gt;
&lt;br /&gt;
    def testXOXOWithSpacesAndNewlines(self):&lt;br /&gt;
        '''unmung some xoxo with spaces in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        d2={'text':'item 1',&lt;br /&gt;
            'description':&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
            'url':'http://example.com/more.xoxo',&lt;br /&gt;
            'title':'title of item 1',&lt;br /&gt;
            'type':'text/xml',&lt;br /&gt;
            'rel':'help'&lt;br /&gt;
            }&lt;br /&gt;
        xoxoAgain = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        #this needs a smarter whitespace-sensitive comparison&lt;br /&gt;
        #self.assertEqual(xoxoSample,xoxoAgain)&lt;br /&gt;
&lt;br /&gt;
    def testSpecialAttributeDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeAndDLDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in plus a &amp;lt;dl&amp;gt; in the same item and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeEncode(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        expectedHTML= '&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;' &lt;br /&gt;
        self.assertEqual(html,expectedHTML)&lt;br /&gt;
        &lt;br /&gt;
    def testSpecialAttributeRoundTripFull(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoText(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoTextOrTitle(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text or title attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testAttentionRoundTrip(self):&lt;br /&gt;
        '''check nested &amp;lt;a&amp;gt; and &amp;lt;dl&amp;gt; and &amp;lt;a&amp;gt; are preserved'''&lt;br /&gt;
        kmattn='''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;''';&lt;br /&gt;
        d = xoxo.fromXOXO(kmattn)&lt;br /&gt;
        newattn = xoxo.toXOXO(d)&lt;br /&gt;
        d2 = xoxo.fromXOXO(newattn)&lt;br /&gt;
        self.assertEqual(newattn,xoxo.toXOXO(d2))&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        self.assertEqual(kmattn,newattn)&lt;br /&gt;
        &lt;br /&gt;
    def testUnicodeRoundtrip(self):&lt;br /&gt;
        '''check unicode characters can go to xoxo and back'''&lt;br /&gt;
        src=unicode('Tantek \xc3\x87elik and a snowman \xe2\x98\x83','utf-8')&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html))&lt;br /&gt;
    def testUtf8Roundtrip(self):&lt;br /&gt;
        '''check utf8 characters can go to xoxo and back'''&lt;br /&gt;
        src='Tantek \xc3\x87elik and a snowman \xe2\x98\x83'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('utf-8'))&lt;br /&gt;
    def testWindows1252Roundtrip(self):&lt;br /&gt;
        '''check 1252 characters can go to xoxo and back'''&lt;br /&gt;
        src='This is an evil\xa0space'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('windows-1252'))&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    unittest.main()&lt;br /&gt;
else:&lt;br /&gt;
    runner = unittest.TextTestRunner()&lt;br /&gt;
    suite = unittest.makeSuite(xoxoTestCases,'test')&lt;br /&gt;
    runner.run(suite)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Java =&lt;br /&gt;
== XOXOWriter.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOWriter {&lt;br /&gt;
&lt;br /&gt;
  public String[] attrs = {&amp;quot;title&amp;quot;,&amp;quot;rel&amp;quot;,&amp;quot;type&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className){&lt;br /&gt;
    return makeXOXO(struct, className, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className,&lt;br /&gt;
                         boolean doNSDeclaration){&lt;br /&gt;
    return makeXOXO(struct, className, 0, doNSDeclaration);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct){&lt;br /&gt;
    return makeXOXO(struct, &amp;quot;xoxo&amp;quot;, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, int depth){&lt;br /&gt;
    return makeXOXO(struct, null, 0, false);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, String className,&lt;br /&gt;
                         int depth, boolean doNSDeclaration){&lt;br /&gt;
    if(struct == null) return &amp;quot;&amp;quot;;&lt;br /&gt;
    StringBuffer sb = new StringBuffer();&lt;br /&gt;
    if(struct instanceof Object[]){&lt;br /&gt;
      struct = Arrays.asList((Object[]) struct);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof List){&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;ol&amp;quot;);&lt;br /&gt;
      if(doNSDeclaration)&lt;br /&gt;
        sb.append(&amp;quot; xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;quot;);&lt;br /&gt;
      if(className != null){&lt;br /&gt;
        sb.append(&amp;quot; class=\&amp;quot;&amp;quot;);&lt;br /&gt;
        sb.append(className);&lt;br /&gt;
        sb.append(&amp;quot;\&amp;quot;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof Map){&lt;br /&gt;
      Map d = new LinkedHashMap((Map) struct);&lt;br /&gt;
      if(d.containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;a href=\&amp;quot;&amp;quot; + d.get(&amp;quot;url&amp;quot;) + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
        Object text;&lt;br /&gt;
        if(d.containsKey(&amp;quot;text&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;text&amp;quot;);&lt;br /&gt;
        }else if(d.containsKey(&amp;quot;title&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
          text = d.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        for(int i=0; i&amp;lt;attrs.length; i++){&lt;br /&gt;
          String xVal = makeXOXO(d.get(attrs[i]),depth+1);&lt;br /&gt;
          if(xVal != null &amp;amp;&amp;amp; !xVal.equals(&amp;quot;&amp;quot;)){&lt;br /&gt;
            sb.append(attrs[i] + &amp;quot;=\&amp;quot;&amp;quot; + xVal + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
          d.remove(attrs[i]);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;gt;&amp;quot; + makeXOXO(text, depth+1) + &amp;quot;&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;text&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;url&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      if(d.size() &amp;gt; 0){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;);&lt;br /&gt;
        for(Iterator i = d.entrySet().iterator(); i.hasNext();){&lt;br /&gt;
          Map.Entry entry = (Map.Entry)i.next();&lt;br /&gt;
          String ddVal = makeXOXO(entry.getValue(),depth+1);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dt&amp;gt;&amp;quot; + entry.getKey() + &amp;quot;&amp;lt;/dt&amp;gt;&amp;quot;);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dd&amp;gt;&amp;quot; + ddVal + &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
    }else if(struct instanceof List){&lt;br /&gt;
      List l = (List) struct;&lt;br /&gt;
      for(Iterator i = l.iterator(); i.hasNext();){&lt;br /&gt;
        Object item = i.next();&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,depth+1) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);&lt;br /&gt;
    }else{&lt;br /&gt;
      sb.append(struct);&lt;br /&gt;
    }&lt;br /&gt;
    return sb.toString();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct){&lt;br /&gt;
    return toXOXO(struct, false, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist, addHTMLWrapper, cssUrl);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;quot;;&lt;br /&gt;
    if(addHTMLWrapper){&lt;br /&gt;
      String s = startHTML;&lt;br /&gt;
      if(cssUrl != null){&lt;br /&gt;
        s += &amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot;&amp;gt;@import \&amp;quot;&amp;quot;&lt;br /&gt;
            + cssUrl + &amp;quot;\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      s += &amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot; + makeXOXO(struct, &amp;quot;xoxo&amp;quot;, false)&lt;br /&gt;
          + &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
      return s;&lt;br /&gt;
    }else{&lt;br /&gt;
      return makeXOXO(struct, &amp;quot;xoxo&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOParser.java ==&lt;br /&gt;
Ceci a besoin de quelques petits ajouts pour gérer les entités XHTML DTD et digits nommés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import org.xml.sax.InputSource;&lt;br /&gt;
import org.xml.sax.SAXException;&lt;br /&gt;
import org.xml.sax.XMLReader;&lt;br /&gt;
import org.xml.sax.Attributes;&lt;br /&gt;
import org.xml.sax.helpers.XMLReaderFactory;&lt;br /&gt;
import org.xml.sax.helpers.DefaultHandler;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
import java.io.InputStream;&lt;br /&gt;
import java.io.StringReader;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
&lt;br /&gt;
public class XOXOParser extends DefaultHandler {&lt;br /&gt;
&lt;br /&gt;
  protected String XHTML_NS = &amp;quot;http://www.w3.org/1999/xhtml&amp;quot;;&lt;br /&gt;
  protected List elStack;&lt;br /&gt;
  protected Map listEls;&lt;br /&gt;
  public List structs;&lt;br /&gt;
  public List xoStack;&lt;br /&gt;
  public List textStack;&lt;br /&gt;
&lt;br /&gt;
  public XOXOParser() {&lt;br /&gt;
    reset();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void pushStruct(Object struct){&lt;br /&gt;
    if(struct instanceof Map &amp;amp;&amp;amp; !((Map) struct).isEmpty()&lt;br /&gt;
        &amp;amp;&amp;amp; structs.get(structs.size()-1) instanceof Map&lt;br /&gt;
        &amp;amp;&amp;amp; ((Map) struct).containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
      // put back the &amp;lt;a&amp;gt;-made one for extra defs&lt;br /&gt;
      xoStack.add(structs.get(structs.size()-1));&lt;br /&gt;
    }else{&lt;br /&gt;
      structs.add(struct);&lt;br /&gt;
      xoStack.add(struct);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void startElement(String nsUri, String localName,&lt;br /&gt;
                           String qName, Attributes atts){&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri.equals(XHTML_NS)){&lt;br /&gt;
      elStack.add(localName);&lt;br /&gt;
    }else{&lt;br /&gt;
      elStack.add(&amp;quot;foo&amp;quot;);&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      Map attmap = new LinkedHashMap();&lt;br /&gt;
      int len = atts.getLength();&lt;br /&gt;
      for(int i=0; i&amp;lt;len; i++){&lt;br /&gt;
        attmap.put(atts.getQName(i),atts.getValue(i));&lt;br /&gt;
      }&lt;br /&gt;
      if(attmap.containsKey(&amp;quot;href&amp;quot;)){&lt;br /&gt;
        attmap.put(&amp;quot;url&amp;quot;,attmap.get(&amp;quot;href&amp;quot;));&lt;br /&gt;
        attmap.remove(&amp;quot;href&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      pushStruct(attmap);&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      pushStruct(new LinkedHashMap());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dt&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void endElement(String nsUri, String localName,&lt;br /&gt;
                         String qName){&lt;br /&gt;
    elStack.remove(elStack.size()-1);&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri != XHTML_NS){&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      String val = (String) textStack.remove(textStack.size()-1);&lt;br /&gt;
      if (val.length() &amp;gt; 0){&lt;br /&gt;
        Map defs = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
        String defVal = (String) defs.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        if(defVal != null &amp;amp;&amp;amp; val.equals(defVal)){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        defVal = (String) defs.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        if(defVal != null &amp;amp;&amp;amp; val.equals(defVal)){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        if(val.length() &amp;gt; 0){&lt;br /&gt;
          defs.put(&amp;quot;text&amp;quot;,val);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      List last = (List) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.add(val);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Object key = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Map last = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.put(key,val);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void characters(char[] ch, int start, int length){&lt;br /&gt;
    if(xoStack.size() &amp;gt; 0&lt;br /&gt;
        &amp;amp;&amp;amp; !listEls.containsKey(elStack.get(elStack.size()-1))){&lt;br /&gt;
      String text = (String) textStack.get(textStack.size()-1);&lt;br /&gt;
      String test = new String(ch,start,length);&lt;br /&gt;
      textStack.set(textStack.size()-1,text+test);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(String s) throws SAXException, IOException{&lt;br /&gt;
    return parse(new InputSource(new StringReader(s)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputStream is) throws SAXException, IOException {&lt;br /&gt;
    return parse(new InputSource(is));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputSource in) throws SAXException, IOException {&lt;br /&gt;
    XMLReader parser = XMLReaderFactory.createXMLReader();&lt;br /&gt;
    parser.setContentHandler(this);&lt;br /&gt;
    parser.parse(in);&lt;br /&gt;
    List returnList = new ArrayList();&lt;br /&gt;
    for(Iterator i = this.structs.iterator(); i.hasNext();){&lt;br /&gt;
      Object thing = i.next();&lt;br /&gt;
      if(thing != null){&lt;br /&gt;
        returnList.add(thing);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    while(returnList.size()==1){&lt;br /&gt;
      if(returnList.get(0) instanceof List){&lt;br /&gt;
        returnList = (List) returnList.get(0);&lt;br /&gt;
      }else{&lt;br /&gt;
        reset();&lt;br /&gt;
        return returnList.get(0);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    reset();&lt;br /&gt;
    return returnList;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void reset(){&lt;br /&gt;
    elStack = new ArrayList();&lt;br /&gt;
    listEls = new HashMap();&lt;br /&gt;
    structs = new ArrayList();&lt;br /&gt;
    xoStack = new ArrayList();&lt;br /&gt;
    textStack = new ArrayList();&lt;br /&gt;
    listEls.put(&amp;quot;ol&amp;quot;,&amp;quot;ol&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;ul&amp;quot;,&amp;quot;ul&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;dl&amp;quot;,&amp;quot;dl&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOTest.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo.tests;&lt;br /&gt;
&lt;br /&gt;
import junit.framework.TestSuite;&lt;br /&gt;
import junit.framework.TestCase;&lt;br /&gt;
import junit.textui.TestRunner;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOWriter;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOParser;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOTest extends TestCase {&lt;br /&gt;
&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    new TestRunner().doRun(new TestSuite(XOXOTest.class));&lt;br /&gt;
  }&lt;br /&gt;
  String XHTML_DEC = &amp;quot;xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot; &amp;quot;;&lt;br /&gt;
  public String simpleListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSimpleList(){&lt;br /&gt;
    String [] numbers = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testStringIntegerList(){&lt;br /&gt;
    Object[] numbers = {new Integer(1),&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String nestedListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testNestedList(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,Arrays.asList(arr)};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testNestedArray(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,arr};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String dictHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testDictionary(){&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, new Integer(1));&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(dictHTML,&lt;br /&gt;
                 xoxo.toXOXO(dict));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String singleHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(singleHTML,&lt;br /&gt;
                 xoxo.toXOXO(item));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testWrapDiffers(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String nowrap = xoxo.toXOXO(item);&lt;br /&gt;
    Object[] itemArr = {item};&lt;br /&gt;
    String wrap = xoxo.toXOXO(Arrays.asList(itemArr),true,null);&lt;br /&gt;
    assertFalse(wrap.equals(nowrap));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;;&lt;br /&gt;
  public String singleWrapHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
  public String endHTML = &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testWrapSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(startHTML + singleWrapHTML + endHTML,&lt;br /&gt;
                 xoxo.toXOXO(item,true,null));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOParser(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      parser.parse(dictHTML);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
     try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListRoundTrip(){&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfDictsRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    Map dict2 = new LinkedHashMap();&lt;br /&gt;
    dict2.put(&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;three&amp;quot;, &amp;quot;four&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;five&amp;quot;, &amp;quot;six&amp;quot;);&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,dict,dict2};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;, Arrays.asList(list1)};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;, Arrays.asList(list2)};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, Arrays.asList(list3)};&lt;br /&gt;
    List testList = Arrays.asList(list4);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, &amp;quot;9&amp;quot;};&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;foo&amp;quot;, Arrays.asList(list1));&lt;br /&gt;
    dict.put(&amp;quot;bar&amp;quot;, Arrays.asList(list2));&lt;br /&gt;
    dict.put(&amp;quot;baz&amp;quot;, Arrays.asList(list3));&lt;br /&gt;
    dict.put(&amp;quot;qux&amp;quot;, Arrays.asList(list4));&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOJunkInContainers(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(junkXOXO);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkElementXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOjunkInElements(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    Object[] ok = {&amp;quot;OK&amp;quot;};&lt;br /&gt;
    Object[] obj ={dict, Arrays.asList(ok)};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(junkElementXOXO);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSpacesNewlines = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt; This item represents the main&amp;quot; +&lt;br /&gt;
      &amp;quot; point we're trying to make.&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOWithSpacesAndNewlines(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;description&amp;quot;,&amp;quot; This item represents the main&amp;quot; +&lt;br /&gt;
        &amp;quot; point we're trying to make.&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;title of item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(xoxoSpacesNewlines);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSample = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public String smartXOXOSample = &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         title=\&amp;quot;title of item 1\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         type=\&amp;quot;text/xml\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply&amp;quot; +&lt;br /&gt;
      &amp;quot; the contents of the &amp;lt;a&amp;gt; element --&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeDecoding(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object xoxoDict = parser.parse(xoxoSample);&lt;br /&gt;
      Object xoxoDict2 = parser.parse(smartXOXOSample);&lt;br /&gt;
      assertEquals(xoxoDict,xoxoDict2);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String specialAttrHTML =  &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot; title=\&amp;quot;sample url\&amp;quot; &amp;quot; +&lt;br /&gt;
      &amp;quot;rel=\&amp;quot;help\&amp;quot; type=\&amp;quot;text/xml\&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeEncode(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    assertEquals(specialAttrHTML,html);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripFull(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoText(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoTextOrTitle(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testUnicodeRoundTrip(){&lt;br /&gt;
    String s = &amp;quot;Tantek Çelik and a snowman ?&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(s);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newString = parser.parse(html);&lt;br /&gt;
      assertEquals(s,newString);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= PHP =&lt;br /&gt;
== xoxolib.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
function getKind($struct)&lt;br /&gt;
{&lt;br /&gt;
    if (!is_array($struct)) return 'string';&lt;br /&gt;
    if (!isset($struct[0]))&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    else if (array_keys($struct)==range(0,count($struct)-1))&lt;br /&gt;
        $result = 'list';&lt;br /&gt;
    else&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    return $result;&lt;br /&gt;
}&lt;br /&gt;
function makeXOXO($struct,$className='')&lt;br /&gt;
{&lt;br /&gt;
    $s='';&lt;br /&gt;
    $kind = getKind($struct);&lt;br /&gt;
    #echo &amp;quot;$kind:\n&amp;quot;;&lt;br /&gt;
    #var_dump($struct);&lt;br /&gt;
    if ($kind=='list')&lt;br /&gt;
        {&lt;br /&gt;
        if ($className)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol class=\&amp;quot;$className\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
        else &lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol&amp;gt;&amp;quot;;&lt;br /&gt;
        foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;li&amp;gt;&amp;quot; . makeXOXO($value) .&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
    else if ($kind=='dictionary')&lt;br /&gt;
        {&lt;br /&gt;
        if (isset($struct['url']))&lt;br /&gt;
            {&lt;br /&gt;
            $s .='&amp;lt;a href=&amp;quot;' .$struct['url']. '&amp;quot; ';&lt;br /&gt;
            if (isset($struct['text']))&lt;br /&gt;
                $text= $struct['text'];&lt;br /&gt;
            else if (isset($struct['title']))&lt;br /&gt;
                $text= $struct['title'];&lt;br /&gt;
            else&lt;br /&gt;
                $text= $struct['url'];&lt;br /&gt;
            foreach (array('title','rel','type') as $attr)&lt;br /&gt;
                if (isset($struct[$attr]))&lt;br /&gt;
                    {&lt;br /&gt;
                    $s .= &amp;quot;$attr=\&amp;quot;&amp;quot; . $struct[$attr] .'&amp;quot; ';&lt;br /&gt;
                    unset($struct[$attr]);&lt;br /&gt;
                    }&lt;br /&gt;
            $s .= &amp;quot;&amp;gt;&amp;quot; . makeXOXO($text) .&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
            unset($struct['url'],$struct['text']);&lt;br /&gt;
            }&lt;br /&gt;
        if (count($struct))&lt;br /&gt;
            {&lt;br /&gt;
            $s .=&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
            foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
                $s .= &amp;quot;&amp;lt;dt&amp;gt;$key&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;quot;. makeXOXO($value) . &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;;&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    else&lt;br /&gt;
        $s .= &amp;quot;$struct&amp;quot;;&lt;br /&gt;
    #echo &amp;quot;returned $s\n&amp;quot;;&lt;br /&gt;
    return $s;&lt;br /&gt;
}&lt;br /&gt;
function toXOXO($struct,$addHTMLWrapper=FALSE,$cssUrl='')&lt;br /&gt;
{&lt;br /&gt;
    if (getKind($struct) != 'list')&lt;br /&gt;
        $struct = array($struct);&lt;br /&gt;
    $xoxo = makeXOXO($struct,'xoxo');&lt;br /&gt;
    if ($addHTMLWrapper)&lt;br /&gt;
        {&lt;br /&gt;
        $s= '&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;';&lt;br /&gt;
        if ($cssUrl) $s .=&amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot; &amp;gt;@import \&amp;quot;$cssUrl\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;$xoxo&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
        return $s;&lt;br /&gt;
        }&lt;br /&gt;
    return $xoxo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function pushStruct($struct,&amp;amp;$structstack,&amp;amp;$xostack,$structType)&lt;br /&gt;
{&lt;br /&gt;
    if (is_array($struct) &amp;amp;&amp;amp; $structType=='dict' &amp;amp;&amp;amp; count($structstack) &amp;amp;&amp;amp; is_array(end($structstack)) &amp;amp;&amp;amp; isset($structstack[count($structstack)-1]['url']) &amp;amp;&amp;amp; end($structstack) != end($xostack))&lt;br /&gt;
        $xostack[] = &amp;amp;$structstack[count($structstack)-1]; # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
    else&lt;br /&gt;
        {&lt;br /&gt;
        $structstack[]=$struct;&lt;br /&gt;
        $xostack[]=&amp;amp;$structstack[count($structstack)-1];&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fromXOXO($html)&lt;br /&gt;
{&lt;br /&gt;
    $structs=array();&lt;br /&gt;
    $xostack=array();&lt;br /&gt;
    $textstack=array('');&lt;br /&gt;
    $dumpStacks=0;&lt;br /&gt;
    $p = xml_parser_create();&lt;br /&gt;
    xml_parse_into_struct($p, $html, $xoxoVals, $xoxoIndex);&lt;br /&gt;
    xml_parser_free($p);&lt;br /&gt;
&lt;br /&gt;
  if($dumpStacks)&lt;br /&gt;
        {&lt;br /&gt;
        echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
        var_dump($xoxoVals);&lt;br /&gt;
        var_dump($xoxoIndex);&lt;br /&gt;
        echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;; &lt;br /&gt;
        }&lt;br /&gt;
    $howmany = sizeof($xoxoVals);&lt;br /&gt;
    &lt;br /&gt;
    #echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    $x = $xoxoIndex['OL'];&lt;br /&gt;
    for ($x=0;$x&amp;lt;$howmany;++$x)&lt;br /&gt;
        {&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'OL' || $xoxoVals[$x]['tag'] == 'DL'|| $xoxoVals[$x]['tag'] == 'UL')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['tag'] == 'DL')&lt;br /&gt;
                $structType = 'dict';&lt;br /&gt;
            else &lt;br /&gt;
                $structType = 'list';&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'open')&lt;br /&gt;
                pushStruct(array(),$structs,$xostack,$structType);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'LI')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
               array_push($xostack[count($xostack)-1],$xoxoVals[$x]['value']);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                array_push($xostack[count($xostack)-1],array_pop($structs));&lt;br /&gt;
                }&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DT')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                array_push($textstack,$xoxoVals[$x]['value']);&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DD')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] = $xoxoVals[$x]['value'];&lt;br /&gt;
                }&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] =array_pop($structs);&lt;br /&gt;
                }&lt;br /&gt;
          if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'A')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $attrs = $xoxoVals[$x]['attributes'];&lt;br /&gt;
                $dict=array();&lt;br /&gt;
                foreach ($attrs as $key=&amp;gt; $value)&lt;br /&gt;
                    {&lt;br /&gt;
                    if ($key=='HREF')&lt;br /&gt;
                        $dict['url'] = $value;&lt;br /&gt;
                    else&lt;br /&gt;
                        $dict[strtolower($key)] = $value;&lt;br /&gt;
                    }&lt;br /&gt;
                $val = $xoxoVals[$x]['value'];&lt;br /&gt;
                if (isset($val) &amp;amp;&amp;amp; ($val != $dict['title']) &amp;amp;&amp;amp; ($val != $dict['url']))&lt;br /&gt;
                    $dict['text'] = $val;&lt;br /&gt;
                pushStruct($dict,$structs,$xostack,'dict');&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
 &lt;br /&gt;
                if($dumpStacks)&lt;br /&gt;
                    {&lt;br /&gt;
                    echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                    var_dump($structs);&lt;br /&gt;
                    var_dump($xostack);&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
     #echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;;&lt;br /&gt;
   while (count($structs) == 1 &amp;amp;&amp;amp; getKind($structs) == 'list')&lt;br /&gt;
        $structs = $structs[0];&lt;br /&gt;
    return $structs;&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== xoxotest.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
include(&amp;quot;xoxolib.php&amp;quot;);&lt;br /&gt;
function assertEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 == $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str2&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function assertArrayEqual($testname,$expected,$returned)&lt;br /&gt;
{&lt;br /&gt;
if ($expected == $returned)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($expected);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($returned);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function failIfEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 != $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;both were&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$l = array('1','2','3');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$s = 'test';&lt;br /&gt;
$html = toXOXO($s);&lt;br /&gt;
assertEqual(&amp;quot;make xoxo from a string&amp;quot;,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$htmlwrap = toXOXO($s,TRUE);&lt;br /&gt;
failIfEqual(&amp;quot;make sure wrapped and unwrapped differ&amp;quot;,html,htmlwrap);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$htmlwrap);&lt;br /&gt;
$csswrap = toXOXO($s,TRUE,&amp;quot;reaptest.css&amp;quot;);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo with css link from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$csswrap);&lt;br /&gt;
$l2 = array('1',array('2','3'));&lt;br /&gt;
$html = toXOXO($l2);&lt;br /&gt;
assertEqual('make xoxo from nested list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from 1-element dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','thing'=&amp;gt;'and another thing...');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and thing','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;thing&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;and another thing...&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','list'=&amp;gt;array('and', 'another','thing...'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;list&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;and&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;another&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;thing...&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from dict in list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;a&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;2&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$l = array('3','2','1');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list to xoxo and back',$l,$newdl);&lt;br /&gt;
$l = array('1',array('a','b'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
&lt;br /&gt;
$l= array('3',array('a','2'),array('b',array('1',array('c','4'))));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'),array('b'=&amp;gt;'1','c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('list of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'two'=&amp;gt;array('c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'url'=&amp;gt;'http://example.com');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts with url to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts with url to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$d = array('test'=&amp;gt; array('1','2'),&lt;br /&gt;
'name'=&amp;gt; 'Kevin','nestlist'=&amp;gt; array('a',array('b','c')),&lt;br /&gt;
'nestdict'=&amp;gt;array('e'=&amp;gt;'6','f'=&amp;gt;'7'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary of lists  to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$d=fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text outside &amp;amp;lt;li&amp;amp;gt; etc is ignored',array(good=&amp;gt;buy),$d);&lt;br /&gt;
&lt;br /&gt;
$l=fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text within &amp;amp;lt;li&amp;amp;gt; but outside a subcontainer is ignored',array(array(good=&amp;gt;buy),array('OK')),$l);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$d2=array('text'=&amp;gt;'item 1',&lt;br /&gt;
    'description'=&amp;gt;&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
    'url'=&amp;gt;'http://example.com/more.xoxo',&lt;br /&gt;
    'title'=&amp;gt;'title of item 1',&lt;br /&gt;
    'type'=&amp;gt;'text/xml',&lt;br /&gt;
    'rel'=&amp;gt;'help');&lt;br /&gt;
assertArrayEqual('unmung some xoxo with spaces in and check result is right',$d2,$d);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (no text)',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (just url)',$d,fromXOXO($html));&lt;br /&gt;
$kmattn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
$d=fromXOXO($kmattn);&lt;br /&gt;
$newattn = toXOXO($d);&lt;br /&gt;
$d2=fromXOXO($newattn);&lt;br /&gt;
assertArrayEqual('attention double round-trip',$d,$d2);&lt;br /&gt;
assertEqual('attention triple round-trip',$newattn,toXOXO($d2));&lt;br /&gt;
assertEqual('attention one round-trip',$kmattn,$newattn);&lt;br /&gt;
$d=array(array(url=&amp;gt;&amp;quot;http://www.boingboing.net/&amp;quot;,title=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://boingboing.net/rss.xml&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;),array(url=&amp;gt;&amp;quot;http://www.financialcryptography.com/&amp;quot;,title=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;));&lt;br /&gt;
$attn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
assertEqual('attention encode',$attn,toXOXO($d));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
== autres implémentations ==&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/xoxo2array.php.txt xoxo2array.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/array2xoxo.php.txt array2xoxo.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/#outlineclasses Outline Classes]&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=41707</id>
		<title>xoxo-sample-code-fr</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=41707"/>
		<updated>2010-01-27T18:29:00Z</updated>

		<summary type="html">&lt;p&gt;Newacct: /* XOXOWriter.java */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Code Echantillon =&lt;br /&gt;
&lt;br /&gt;
Un paquet général de code échantillon open source, ([http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0]) pour lire et écrire des fichiers [[xoxo-fr|xoxo]] en Python et Java (avec Perl, PHP, ... à suivre).&lt;br /&gt;
= Python =&lt;br /&gt;
== xoxo.py ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;xoxo.py - a utility module for transforming to and from the XHTMLOutlines format XOXO http://microformats.org/wiki/xoxo&lt;br /&gt;
toXOXO takes a Python datastructure (tuples, lists or dictionaries, arbitrarily nested) and returns a XOXO representation of it.&lt;br /&gt;
fromXOXO parses an XHTML file for a xoxo list and returns the structure&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__version__ = &amp;quot;0.9&amp;quot;&lt;br /&gt;
__date__ = &amp;quot;2005-11-02&amp;quot;&lt;br /&gt;
__author__ = &amp;quot;Kevin Marks &amp;lt;kmarks@technorati.com&amp;gt;&amp;quot;&lt;br /&gt;
__copyright__ = &amp;quot;Copyright 2004-2006, Kevin Marks &amp;amp; Technorati&amp;quot;&lt;br /&gt;
__license__ = &amp;quot;http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0&amp;quot;&lt;br /&gt;
__credits__ = &amp;quot;&amp;quot;&amp;quot;Tantek Çelik and Mark Pilgrim for data structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__history__ = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
TODO: add &amp;lt;title&amp;gt; tag&lt;br /&gt;
TODO: add a proper profile link&lt;br /&gt;
0.9 smarter parsing for encoding and partial markup; fix dangling dictionary case&lt;br /&gt;
0.8 work in unicode then render to utf-8&lt;br /&gt;
0.7 initial encoding support - just utf-8 for now&lt;br /&gt;
0.6 support the special behavior for url properties  to/from &amp;lt;a&amp;gt;&lt;br /&gt;
0.5 fix some awkward side effects of whitespace and text outside our expected tags; simplify writing code&lt;br /&gt;
0.4 add correct XHTML headers so it validates&lt;br /&gt;
0.3 read/write version; fixed invalid nested list generation;&lt;br /&gt;
0.1 first write-only version&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    True, False&lt;br /&gt;
except NameError:&lt;br /&gt;
    True, False = not not 1, not 1&lt;br /&gt;
containerTags={'ol':False,'ul':False,'dl':False}&lt;br /&gt;
import sgmllib, urllib, urlparse, re,codecs&lt;br /&gt;
&lt;br /&gt;
def toUnicode(key):&lt;br /&gt;
    if type(key) == type(u'unicode'):&lt;br /&gt;
        uKey= key&lt;br /&gt;
    else:&lt;br /&gt;
        try: &lt;br /&gt;
            uKey=unicode(key,'utf-8')&lt;br /&gt;
        except:&lt;br /&gt;
            uKey=unicode(key,'windows_1252')&lt;br /&gt;
    return uKey&lt;br /&gt;
&lt;br /&gt;
def makeXOXO(struct,className=None):&lt;br /&gt;
    s=u''&lt;br /&gt;
    if isinstance(struct,list) or isinstance(struct,tuple):&lt;br /&gt;
        if className:&lt;br /&gt;
            s += u'&amp;lt;ol class=&amp;quot;%s&amp;quot;&amp;gt;' % className&lt;br /&gt;
        else:&lt;br /&gt;
            s+= u&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;&lt;br /&gt;
        for item in struct:&lt;br /&gt;
            s+=u&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,None)+&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
        s +=u&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;br /&gt;
    elif isinstance(struct,dict):&lt;br /&gt;
        d=struct.copy()&lt;br /&gt;
        if 'url' in d:&lt;br /&gt;
            uURL=toUnicode(d['url'])&lt;br /&gt;
            s+=u'&amp;lt;a href=&amp;quot;%s&amp;quot; ' % uURL&lt;br /&gt;
            text =  d.get('text',d.get('title',uURL))&lt;br /&gt;
            for attr in ('title','rel','type'):&lt;br /&gt;
                if attr in d:&lt;br /&gt;
                    xVal = makeXOXO(d[attr],None)&lt;br /&gt;
                    s +=u'%s=&amp;quot;%s&amp;quot; ' % (attr,xVal)&lt;br /&gt;
                    del d[attr]&lt;br /&gt;
            s +=u'&amp;gt;%s&amp;lt;/a&amp;gt;' % makeXOXO(text,None)&lt;br /&gt;
            if 'text' in d:&lt;br /&gt;
                del d['text']&lt;br /&gt;
            del d['url']&lt;br /&gt;
        if len(d):&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;&lt;br /&gt;
            for key,value in d.items():&lt;br /&gt;
                xVal = makeXOXO(value,None)&lt;br /&gt;
                uKey=toUnicode(key)&lt;br /&gt;
                s+= u'&amp;lt;dt&amp;gt;%s&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;%s&amp;lt;/dd&amp;gt;' % (uKey, xVal)&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
    elif type(struct) == type(u'unicode'):&lt;br /&gt;
        s+=struct&lt;br /&gt;
    else:&lt;br /&gt;
        if type(struct)!=type(' '):&lt;br /&gt;
            struct=str(struct)&lt;br /&gt;
        s += toUnicode(struct)&lt;br /&gt;
    return s&lt;br /&gt;
class AttrParser(sgmllib.SGMLParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        sgmllib.SGMLParser.__init__(self)&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.encoding='utf-8'&lt;br /&gt;
    def cleanText(self,inText):&lt;br /&gt;
        if type(inText) == type(u'unicode'):&lt;br /&gt;
            inText = inText.encode(self.encoding,'replace')&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.reset()&lt;br /&gt;
        self.feed(inText)&lt;br /&gt;
        return ''.join(self.text)&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        if 'ascii' in encoding:&lt;br /&gt;
            encoding='windows_1252' # so we don't throw an exception on high-bit set chars in there by mistake&lt;br /&gt;
        if encoding and not encoding =='text/html':&lt;br /&gt;
            try:&lt;br /&gt;
                canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                self.encoding = encoding&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    encoding='japanese.' +encoding&lt;br /&gt;
                    canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                    self.encoding = encoding&lt;br /&gt;
                except:&lt;br /&gt;
                    print &amp;quot;can't deal with encoding %s&amp;quot; % encoding&lt;br /&gt;
                    &lt;br /&gt;
    def handle_entityref(self, ref):&lt;br /&gt;
        # called for each entity reference, e.g. for &amp;quot;&amp;amp;copy;&amp;quot;, ref will be &amp;quot;copy&amp;quot;&lt;br /&gt;
        # map through to unicode where we can&lt;br /&gt;
        try:&lt;br /&gt;
            entity =htmlentitydefs.name2codepoint[ref]&lt;br /&gt;
            self.handleUnicodeData(unichr(entity))&lt;br /&gt;
        except:&lt;br /&gt;
            try:&lt;br /&gt;
                handle_charref(ref) # deal with char-ref's missing the '#' (see Akma)&lt;br /&gt;
            except:&lt;br /&gt;
                self.handle_data(&amp;quot;&amp;amp;%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
    def handle_charref(self, ref):&lt;br /&gt;
        # called for each character reference, e.g. for &amp;quot;&amp;amp;#160;&amp;quot;, ref will be &amp;quot;160&amp;quot;&lt;br /&gt;
        # Reconstruct the original character reference.&lt;br /&gt;
        try:&lt;br /&gt;
            if ref[0]=='x':&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref[1:],16)))&lt;br /&gt;
            else:&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref)))&lt;br /&gt;
        except:&lt;br /&gt;
            self.handle_data(&amp;quot;&amp;amp;#%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
# called for each block of plain text, i.e. outside of any tag and&lt;br /&gt;
# not containing any character or entity references&lt;br /&gt;
    def handle_data(self, text):&lt;br /&gt;
        if type(text)==type(u' '):&lt;br /&gt;
            self.handleUnicodeData(text)&lt;br /&gt;
        if self.encoding== 'utf-8':&lt;br /&gt;
            try:&lt;br /&gt;
                uText = unicode(text,self.encoding) #utf-8 is pretty clear when it is wrong&lt;br /&gt;
            except:&lt;br /&gt;
                uText = unicode(text,'windows_1252','ignore') # and this is the likely wrongness&lt;br /&gt;
        else:&lt;br /&gt;
            uText = unicode(text,self.encoding,'replace') # if they have really broken encoding, (eg lots of shift-JIS blogs)&lt;br /&gt;
        self.handleUnicodeData(uText)&lt;br /&gt;
    def handleUnicodeData(self, uText):&lt;br /&gt;
        self.text.append(uText)&lt;br /&gt;
        &lt;br /&gt;
class xoxoParser(AttrParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        AttrParser.__init__(self)&lt;br /&gt;
        self.structs=[]&lt;br /&gt;
        self.xostack=[]&lt;br /&gt;
        self.textstack=['']&lt;br /&gt;
        self.attrparse = AttrParser()&lt;br /&gt;
    def normalize_attrs(self, attrs):&lt;br /&gt;
        attrs = [(k.lower(), self.attrparse.cleanText(v)) for k, v in attrs]&lt;br /&gt;
        attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs]&lt;br /&gt;
        return attrs&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        AttrParser.setEncoding(self,encoding)&lt;br /&gt;
        self.attrparse.setEncoding(encoding)&lt;br /&gt;
    def pushStruct(self,struct):&lt;br /&gt;
        if type(struct) == type({}) and len(struct)==0 and len(self.structs) and type(self.structs[-1]) == type({}) and 'url' in self.structs[-1] and self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            self.xostack.append(self.structs[-1]) # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
        else:&lt;br /&gt;
            self.structs.append(struct)&lt;br /&gt;
            self.xostack.append(self.structs[-1])&lt;br /&gt;
    def do_meta(self, attributes):&lt;br /&gt;
        atts = dict(self.normalize_attrs(attributes))&lt;br /&gt;
        #print atts.encode('utf-8')&lt;br /&gt;
        if 'http-equiv' in atts:&lt;br /&gt;
            if atts['http-equiv'].lower() == &amp;quot;content-type&amp;quot;:&lt;br /&gt;
                if 'content' in atts:&lt;br /&gt;
                    encoding = atts['content'].split('charset=')[-1]&lt;br /&gt;
                    self.setEncoding(encoding)&lt;br /&gt;
    def start_a(self,attrs):&lt;br /&gt;
        attrsD = dict(self.normalize_attrs(attrs))&lt;br /&gt;
        attrsD['url']= attrsD.get('href','')&lt;br /&gt;
        if 'href' in attrsD:&lt;br /&gt;
            del attrsD['href']&lt;br /&gt;
        self.pushStruct(attrsD)&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_a(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        if val: &lt;br /&gt;
            if self.xostack[-1].get('title','') == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if self.xostack[-1]['url'] == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if val:&lt;br /&gt;
                self.xostack[-1]['text']=val&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_dl(self,attrs):&lt;br /&gt;
        self.pushStruct({})&lt;br /&gt;
    def end_dl(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ol(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ol(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ul(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ul(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_li(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_li(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        while self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
        if type(val) == type(' ') or type(val) == type(u' '):&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
    def start_dt(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dt(self):&lt;br /&gt;
        pass&lt;br /&gt;
    def start_dd(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dd(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        key = self.textstack.pop()&lt;br /&gt;
        if self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
        self.xostack[-1][key]=val&lt;br /&gt;
    def handleUnicodeData(self, text):&lt;br /&gt;
        if len(self.stack) and containerTags.get(self.stack[-1],True): #skip text not within an element&lt;br /&gt;
            self.textstack[-1] += text&lt;br /&gt;
def toXOXO(struct,addHTMLWrapper=False,cssUrl=''):&lt;br /&gt;
    if type(struct) ==type((1,))or type(struct) ==type([1,]):&lt;br /&gt;
        inStruct = struct&lt;br /&gt;
    else:&lt;br /&gt;
        inStruct = [struct]&lt;br /&gt;
    if addHTMLWrapper:&lt;br /&gt;
        s= u'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;'''&lt;br /&gt;
        if cssUrl:&lt;br /&gt;
            s+=u'&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;%s&amp;quot;;&amp;lt;/style&amp;gt;' % cssUrl&lt;br /&gt;
        s+=u&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot; % makeXOXO(inStruct,'xoxo')&lt;br /&gt;
        return s.encode('utf-8')&lt;br /&gt;
    else:&lt;br /&gt;
        return makeXOXO(inStruct,'xoxo').encode('utf-8')&lt;br /&gt;
    &lt;br /&gt;
def fromXOXO(html):&lt;br /&gt;
    parser = xoxoParser()&lt;br /&gt;
    #parser.feed(unicode(html,'utf-8'))&lt;br /&gt;
    parser.feed(html)&lt;br /&gt;
    #print parser.structs&lt;br /&gt;
    structs=[struct for struct in parser.structs if struct]&lt;br /&gt;
    #print structs&lt;br /&gt;
    while len(structs) ==1 and type(structs)==type([1,]):&lt;br /&gt;
        structs=structs[0]&lt;br /&gt;
    return structs&lt;br /&gt;
&lt;br /&gt;
# Allow direct invocation&lt;br /&gt;
# Read HTML from URL, parse into data structures, then re-output&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  if len(sys.argv) &amp;lt; 2: raise SystemExit(&amp;quot;Usage: &amp;quot;+sys.argv[0]+&amp;quot; url\n&amp;quot;+__doc__)&lt;br /&gt;
  url=sys.argv[1]&lt;br /&gt;
  file = urllib.urlopen(url)&lt;br /&gt;
  html=file.read(-1)&lt;br /&gt;
  file.close&lt;br /&gt;
  s=fromXOXO(html)&lt;br /&gt;
  p=toXOXO(s,True)&lt;br /&gt;
  print p&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== testxoxo.py  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;testxoxo.py &lt;br /&gt;
Unit tests for xoxo.py&lt;br /&gt;
This file tests the functions in xoxo.py &lt;br /&gt;
The underlying model here is http://diveintopython.org/unit_testing/index.html &lt;br /&gt;
&lt;br /&gt;
run from command line with&lt;br /&gt;
python testxoxo.py -v&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import xoxo&lt;br /&gt;
reload(xoxo)&lt;br /&gt;
import unittest&lt;br /&gt;
&lt;br /&gt;
class xoxoTestCases(unittest.TestCase):&lt;br /&gt;
    &lt;br /&gt;
    def testSimpleList(self):&lt;br /&gt;
        '''make a xoxo file from a list'''&lt;br /&gt;
        l = ['1','2','3']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
    def testNestedList(self):&lt;br /&gt;
        '''make a xoxo file from a list with a list in'''&lt;br /&gt;
        l = ['1',['2','3']]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testDictionary(self):&lt;br /&gt;
        '''make a xoxo file from a dictionary'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testSingleItem(self):&lt;br /&gt;
        '''make a xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testWrapDiffers(self):&lt;br /&gt;
        '''make a xoxo file from a string with and without html wrapper and check they are different'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        htmlwrap =  xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.failIfEqual(html,htmlwrap)&lt;br /&gt;
&lt;br /&gt;
    def testWrapSingleItem(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testWrapItemWithCSS(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True,cssUrl='reaptest.css')&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
        &lt;br /&gt;
    def testDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary wiht an url in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)    &lt;br /&gt;
    def testNestedDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with a dict in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionariesWithURLsRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict with an url into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin','url':'http://slashdot.org'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testListRoundTrip(self):&lt;br /&gt;
        ''' make a list into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3','2','1']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofDictsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Dicts into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',{'a':'2'},{'b':'1','c':'4'}]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofListsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Lists into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',['a','2'],['b',['1',['c','4']]]]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testDictofListsRoundTrip(self):&lt;br /&gt;
        ''' make a dict with lists in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':['1','2'],&lt;br /&gt;
        'name':'Kevin',&lt;br /&gt;
        'nestlist':['a',['b','c']],&lt;br /&gt;
        'nestdict':{'e':'6','f':'7'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInContainers(self):&lt;br /&gt;
        '''make sure text outside &amp;lt;li&amp;gt; etc is ignored'''&lt;br /&gt;
        d=xoxo.fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(d,{'good': 'buy'})&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInElements(self):&lt;br /&gt;
        '''make sure text within &amp;lt;li&amp;gt; but outside a subcontainer is ignored'''&lt;br /&gt;
        l=xoxo.fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(l,[{'good': 'buy'},['OK']])&lt;br /&gt;
&lt;br /&gt;
    def testXOXOWithSpacesAndNewlines(self):&lt;br /&gt;
        '''unmung some xoxo with spaces in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        d2={'text':'item 1',&lt;br /&gt;
            'description':&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
            'url':'http://example.com/more.xoxo',&lt;br /&gt;
            'title':'title of item 1',&lt;br /&gt;
            'type':'text/xml',&lt;br /&gt;
            'rel':'help'&lt;br /&gt;
            }&lt;br /&gt;
        xoxoAgain = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        #this needs a smarter whitespace-sensitive comparison&lt;br /&gt;
        #self.assertEqual(xoxoSample,xoxoAgain)&lt;br /&gt;
&lt;br /&gt;
    def testSpecialAttributeDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeAndDLDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in plus a &amp;lt;dl&amp;gt; in the same item and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeEncode(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        expectedHTML= '&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;' &lt;br /&gt;
        self.assertEqual(html,expectedHTML)&lt;br /&gt;
        &lt;br /&gt;
    def testSpecialAttributeRoundTripFull(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoText(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoTextOrTitle(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text or title attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testAttentionRoundTrip(self):&lt;br /&gt;
        '''check nested &amp;lt;a&amp;gt; and &amp;lt;dl&amp;gt; and &amp;lt;a&amp;gt; are preserved'''&lt;br /&gt;
        kmattn='''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;''';&lt;br /&gt;
        d = xoxo.fromXOXO(kmattn)&lt;br /&gt;
        newattn = xoxo.toXOXO(d)&lt;br /&gt;
        d2 = xoxo.fromXOXO(newattn)&lt;br /&gt;
        self.assertEqual(newattn,xoxo.toXOXO(d2))&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        self.assertEqual(kmattn,newattn)&lt;br /&gt;
        &lt;br /&gt;
    def testUnicodeRoundtrip(self):&lt;br /&gt;
        '''check unicode characters can go to xoxo and back'''&lt;br /&gt;
        src=unicode('Tantek \xc3\x87elik and a snowman \xe2\x98\x83','utf-8')&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html))&lt;br /&gt;
    def testUtf8Roundtrip(self):&lt;br /&gt;
        '''check utf8 characters can go to xoxo and back'''&lt;br /&gt;
        src='Tantek \xc3\x87elik and a snowman \xe2\x98\x83'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('utf-8'))&lt;br /&gt;
    def testWindows1252Roundtrip(self):&lt;br /&gt;
        '''check 1252 characters can go to xoxo and back'''&lt;br /&gt;
        src='This is an evil\xa0space'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('windows-1252'))&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    unittest.main()&lt;br /&gt;
else:&lt;br /&gt;
    runner = unittest.TextTestRunner()&lt;br /&gt;
    suite = unittest.makeSuite(xoxoTestCases,'test')&lt;br /&gt;
    runner.run(suite)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Java =&lt;br /&gt;
== XOXOWriter.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOWriter {&lt;br /&gt;
&lt;br /&gt;
  public String[] attrs = {&amp;quot;title&amp;quot;,&amp;quot;rel&amp;quot;,&amp;quot;type&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className){&lt;br /&gt;
    return makeXOXO(struct, className, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className,&lt;br /&gt;
                         boolean doNSDeclaration){&lt;br /&gt;
    return makeXOXO(struct, className, 0, doNSDeclaration);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct){&lt;br /&gt;
    return makeXOXO(struct, &amp;quot;xoxo&amp;quot;, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, int depth){&lt;br /&gt;
    return makeXOXO(struct, null, 0, false);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, String className,&lt;br /&gt;
                         int depth, boolean doNSDeclaration){&lt;br /&gt;
    if(struct == null) return &amp;quot;&amp;quot;;&lt;br /&gt;
    StringBuffer sb = new StringBuffer();&lt;br /&gt;
    if(struct instanceof Object[]){&lt;br /&gt;
      struct = Arrays.asList((Object[]) struct);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof List){&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;ol&amp;quot;);&lt;br /&gt;
      if(doNSDeclaration)&lt;br /&gt;
        sb.append(&amp;quot; xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;quot;);&lt;br /&gt;
      if(className != null){&lt;br /&gt;
        sb.append(&amp;quot; class=\&amp;quot;&amp;quot;);&lt;br /&gt;
        sb.append(className);&lt;br /&gt;
        sb.append(&amp;quot;\&amp;quot;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof Map){&lt;br /&gt;
      Map d = new LinkedHashMap((Map) struct);&lt;br /&gt;
      if(d.containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;a href=\&amp;quot;&amp;quot; + d.get(&amp;quot;url&amp;quot;) + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
        Object text;&lt;br /&gt;
        if(d.containsKey(&amp;quot;text&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;text&amp;quot;);&lt;br /&gt;
        }else if(d.containsKey(&amp;quot;title&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
          text = d.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        for(int i=0; i&amp;lt;attrs.length; i++){&lt;br /&gt;
          String xVal = makeXOXO(d.get(attrs[i]),depth+1);&lt;br /&gt;
          if(xVal != null &amp;amp;&amp;amp; !xVal.equals(&amp;quot;&amp;quot;)){&lt;br /&gt;
            sb.append(attrs[i] + &amp;quot;=\&amp;quot;&amp;quot; + xVal + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
          d.remove(attrs[i]);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;gt;&amp;quot; + makeXOXO(text, depth+1) + &amp;quot;&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;text&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;url&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      if(d.size() &amp;gt; 0){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;);&lt;br /&gt;
        for(Iterator i = d.entrySet().iterator(); i.hasNext();){&lt;br /&gt;
          Map.Entry entry = (Map.Entry)i.next();&lt;br /&gt;
          String ddVal = makeXOXO(entry.getValue(),depth+1);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dt&amp;gt;&amp;quot; + entry.getKey() + &amp;quot;&amp;lt;/dt&amp;gt;&amp;quot;);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dd&amp;gt;&amp;quot; + ddVal + &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
    }else if(struct instanceof List){&lt;br /&gt;
      List l = (List) struct;&lt;br /&gt;
      for(Iterator i = l.iterator(); i.hasNext();){&lt;br /&gt;
        Object item = i.next();&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,depth+1) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);&lt;br /&gt;
    }else{&lt;br /&gt;
      sb.append(struct);&lt;br /&gt;
    }&lt;br /&gt;
    return sb.toString();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct){&lt;br /&gt;
    return toXOXO(struct, false, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist, addHTMLWrapper, cssUrl);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;quot;;&lt;br /&gt;
    if(addHTMLWrapper){&lt;br /&gt;
      String s = startHTML;&lt;br /&gt;
      if(cssUrl != null){&lt;br /&gt;
        s += &amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot;&amp;gt;@import \&amp;quot;&amp;quot;&lt;br /&gt;
            + cssUrl + &amp;quot;\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      s += &amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot; + makeXOXO(struct, &amp;quot;xoxo&amp;quot;, false)&lt;br /&gt;
          + &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
      return s;&lt;br /&gt;
    }else{&lt;br /&gt;
      return makeXOXO(struct, &amp;quot;xoxo&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOParser.java ==&lt;br /&gt;
Ceci a besoin de quelques petits ajouts pour gérer les entités XHTML DTD et digits nommés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import org.xml.sax.InputSource;&lt;br /&gt;
import org.xml.sax.SAXException;&lt;br /&gt;
import org.xml.sax.XMLReader;&lt;br /&gt;
import org.xml.sax.Attributes;&lt;br /&gt;
import org.xml.sax.helpers.XMLReaderFactory;&lt;br /&gt;
import org.xml.sax.helpers.DefaultHandler;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
import java.io.InputStream;&lt;br /&gt;
import java.io.StringReader;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
&lt;br /&gt;
public class XOXOParser extends DefaultHandler {&lt;br /&gt;
&lt;br /&gt;
  protected String XHTML_NS = &amp;quot;http://www.w3.org/1999/xhtml&amp;quot;;&lt;br /&gt;
  protected List elStack;&lt;br /&gt;
  protected Map listEls;&lt;br /&gt;
  public List structs;&lt;br /&gt;
  public List xoStack;&lt;br /&gt;
  public List textStack;&lt;br /&gt;
&lt;br /&gt;
  public XOXOParser() {&lt;br /&gt;
    reset();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void pushStruct(Object struct){&lt;br /&gt;
    if((struct instanceof Map) &amp;amp;&amp;amp; (((Map) struct).size() &amp;gt; 0)&lt;br /&gt;
        &amp;amp;&amp;amp; (structs.get(structs.size()-1) instanceof Map)&lt;br /&gt;
        &amp;amp;&amp;amp; (((Map) struct).containsKey(&amp;quot;url&amp;quot;))){&lt;br /&gt;
      // put back the &amp;lt;a&amp;gt;-made one for extra defs&lt;br /&gt;
      xoStack.add(structs.get(structs.size()-1));&lt;br /&gt;
    }else{&lt;br /&gt;
      structs.add(struct);&lt;br /&gt;
      xoStack.add(struct);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void startElement(String nsUri, String localName,&lt;br /&gt;
                           String qName, Attributes atts){&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri.equals(XHTML_NS)){&lt;br /&gt;
      elStack.add(localName);&lt;br /&gt;
    }else{&lt;br /&gt;
      elStack.add(&amp;quot;foo&amp;quot;);&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      Map attmap = new LinkedHashMap();&lt;br /&gt;
      int len = atts.getLength();&lt;br /&gt;
      for(int i=0; i&amp;lt;len; i++){&lt;br /&gt;
        attmap.put(atts.getQName(i),atts.getValue(i));&lt;br /&gt;
      }&lt;br /&gt;
      if(attmap.containsKey(&amp;quot;href&amp;quot;)){&lt;br /&gt;
        attmap.put(&amp;quot;url&amp;quot;,attmap.get(&amp;quot;href&amp;quot;));&lt;br /&gt;
        attmap.remove(&amp;quot;href&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      pushStruct(attmap);&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      pushStruct(new LinkedHashMap());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dt&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void endElement(String nsUri, String localName,&lt;br /&gt;
                         String qName){&lt;br /&gt;
    elStack.remove(elStack.size()-1);&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri != XHTML_NS){&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      String val = (String) textStack.remove(textStack.size()-1);&lt;br /&gt;
      if (val.length() &amp;gt; 0){&lt;br /&gt;
        Map defs = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
        String defVal = (String) defs.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        if((defVal != null) &amp;amp;&amp;amp; (val.equals(defVal))){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        defVal = (String) defs.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        if((defVal != null) &amp;amp;&amp;amp; (val.equals(defVal))){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        if(val.length() &amp;gt; 0){&lt;br /&gt;
          defs.put(&amp;quot;text&amp;quot;,val);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      List last = (List) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.add(val);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Object key = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Map last = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.put(key,val);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void characters(char[] ch, int start, int length){&lt;br /&gt;
    if((xoStack.size() &amp;gt; 0)&lt;br /&gt;
        &amp;amp;&amp;amp; (!listEls.containsKey(elStack.get(elStack.size()-1)))){&lt;br /&gt;
      String text = (String) textStack.get(textStack.size()-1);&lt;br /&gt;
      String test = new String(ch,start,length);&lt;br /&gt;
      textStack.set(textStack.size()-1,text+test);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(String s) throws SAXException, IOException{&lt;br /&gt;
    return parse(new InputSource(new StringReader(s)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputStream is) throws SAXException, IOException {&lt;br /&gt;
    return parse(new InputSource(is));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputSource in) throws SAXException, IOException {&lt;br /&gt;
    XMLReader parser = XMLReaderFactory.createXMLReader();&lt;br /&gt;
    parser.setContentHandler(this);&lt;br /&gt;
    parser.parse(in);&lt;br /&gt;
    List returnList = new ArrayList();&lt;br /&gt;
    for(Iterator i = this.structs.iterator(); i.hasNext();){&lt;br /&gt;
      Object thing = i.next();&lt;br /&gt;
      if(thing != null){&lt;br /&gt;
        returnList.add(thing);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    while((returnList.size()==1)){&lt;br /&gt;
      if(returnList.get(0) instanceof List){&lt;br /&gt;
        returnList = (List) returnList.get(0);&lt;br /&gt;
      }else{&lt;br /&gt;
        reset();&lt;br /&gt;
        return returnList.get(0);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    reset();&lt;br /&gt;
    return returnList;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void reset(){&lt;br /&gt;
    elStack = new ArrayList();&lt;br /&gt;
    listEls = new HashMap();&lt;br /&gt;
    structs = new ArrayList();&lt;br /&gt;
    xoStack = new ArrayList();&lt;br /&gt;
    textStack = new ArrayList();&lt;br /&gt;
    listEls.put(&amp;quot;ol&amp;quot;,&amp;quot;ol&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;ul&amp;quot;,&amp;quot;ul&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;dl&amp;quot;,&amp;quot;dl&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOTest.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo.tests;&lt;br /&gt;
&lt;br /&gt;
import junit.framework.TestSuite;&lt;br /&gt;
import junit.framework.TestCase;&lt;br /&gt;
import junit.textui.TestRunner;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOWriter;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOParser;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOTest extends TestCase {&lt;br /&gt;
&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    new TestRunner().doRun(new TestSuite(XOXOTest.class));&lt;br /&gt;
  }&lt;br /&gt;
  String XHTML_DEC = &amp;quot;xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot; &amp;quot;;&lt;br /&gt;
  public String simpleListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSimpleList(){&lt;br /&gt;
    String [] numbers = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testStringIntegerList(){&lt;br /&gt;
    Object[] numbers = {new Integer(1),&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String nestedListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testNestedList(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,Arrays.asList(arr)};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testNestedArray(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,arr};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String dictHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testDictionary(){&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, new Integer(1));&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(dictHTML,&lt;br /&gt;
                 xoxo.toXOXO(dict));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String singleHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(singleHTML,&lt;br /&gt;
                 xoxo.toXOXO(item));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testWrapDiffers(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String nowrap = xoxo.toXOXO(item);&lt;br /&gt;
    Object[] itemArr = {item};&lt;br /&gt;
    String wrap = xoxo.toXOXO(Arrays.asList(itemArr),true,null);&lt;br /&gt;
    assertFalse(wrap.equals(nowrap));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;;&lt;br /&gt;
  public String singleWrapHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
  public String endHTML = &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testWrapSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(startHTML + singleWrapHTML + endHTML,&lt;br /&gt;
                 xoxo.toXOXO(item,true,null));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOParser(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      parser.parse(dictHTML);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
     try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListRoundTrip(){&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfDictsRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    Map dict2 = new LinkedHashMap();&lt;br /&gt;
    dict2.put(&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;three&amp;quot;, &amp;quot;four&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;five&amp;quot;, &amp;quot;six&amp;quot;);&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,dict,dict2};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;, Arrays.asList(list1)};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;, Arrays.asList(list2)};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, Arrays.asList(list3)};&lt;br /&gt;
    List testList = Arrays.asList(list4);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, &amp;quot;9&amp;quot;};&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;foo&amp;quot;, Arrays.asList(list1));&lt;br /&gt;
    dict.put(&amp;quot;bar&amp;quot;, Arrays.asList(list2));&lt;br /&gt;
    dict.put(&amp;quot;baz&amp;quot;, Arrays.asList(list3));&lt;br /&gt;
    dict.put(&amp;quot;qux&amp;quot;, Arrays.asList(list4));&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOJunkInContainers(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(junkXOXO);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkElementXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOjunkInElements(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    Object[] ok = {&amp;quot;OK&amp;quot;};&lt;br /&gt;
    Object[] obj ={dict, Arrays.asList(ok)};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(junkElementXOXO);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSpacesNewlines = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt; This item represents the main&amp;quot; +&lt;br /&gt;
      &amp;quot; point we're trying to make.&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOWithSpacesAndNewlines(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;description&amp;quot;,&amp;quot; This item represents the main&amp;quot; +&lt;br /&gt;
        &amp;quot; point we're trying to make.&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;title of item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(xoxoSpacesNewlines);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSample = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public String smartXOXOSample = &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         title=\&amp;quot;title of item 1\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         type=\&amp;quot;text/xml\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply&amp;quot; +&lt;br /&gt;
      &amp;quot; the contents of the &amp;lt;a&amp;gt; element --&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeDecoding(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object xoxoDict = parser.parse(xoxoSample);&lt;br /&gt;
      Object xoxoDict2 = parser.parse(smartXOXOSample);&lt;br /&gt;
      assertEquals(xoxoDict,xoxoDict2);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String specialAttrHTML =  &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot; title=\&amp;quot;sample url\&amp;quot; &amp;quot; +&lt;br /&gt;
      &amp;quot;rel=\&amp;quot;help\&amp;quot; type=\&amp;quot;text/xml\&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeEncode(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    assertEquals(specialAttrHTML,html);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripFull(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoText(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoTextOrTitle(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testUnicodeRoundTrip(){&lt;br /&gt;
    String s = &amp;quot;Tantek Çelik and a snowman ?&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(s);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newString = parser.parse(html);&lt;br /&gt;
      assertEquals(s,newString);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= PHP =&lt;br /&gt;
== xoxolib.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
function getKind($struct)&lt;br /&gt;
{&lt;br /&gt;
    if (!is_array($struct)) return 'string';&lt;br /&gt;
    if (!isset($struct[0]))&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    else if (array_keys($struct)==range(0,count($struct)-1))&lt;br /&gt;
        $result = 'list';&lt;br /&gt;
    else&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    return $result;&lt;br /&gt;
}&lt;br /&gt;
function makeXOXO($struct,$className='')&lt;br /&gt;
{&lt;br /&gt;
    $s='';&lt;br /&gt;
    $kind = getKind($struct);&lt;br /&gt;
    #echo &amp;quot;$kind:\n&amp;quot;;&lt;br /&gt;
    #var_dump($struct);&lt;br /&gt;
    if ($kind=='list')&lt;br /&gt;
        {&lt;br /&gt;
        if ($className)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol class=\&amp;quot;$className\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
        else &lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol&amp;gt;&amp;quot;;&lt;br /&gt;
        foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;li&amp;gt;&amp;quot; . makeXOXO($value) .&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
    else if ($kind=='dictionary')&lt;br /&gt;
        {&lt;br /&gt;
        if (isset($struct['url']))&lt;br /&gt;
            {&lt;br /&gt;
            $s .='&amp;lt;a href=&amp;quot;' .$struct['url']. '&amp;quot; ';&lt;br /&gt;
            if (isset($struct['text']))&lt;br /&gt;
                $text= $struct['text'];&lt;br /&gt;
            else if (isset($struct['title']))&lt;br /&gt;
                $text= $struct['title'];&lt;br /&gt;
            else&lt;br /&gt;
                $text= $struct['url'];&lt;br /&gt;
            foreach (array('title','rel','type') as $attr)&lt;br /&gt;
                if (isset($struct[$attr]))&lt;br /&gt;
                    {&lt;br /&gt;
                    $s .= &amp;quot;$attr=\&amp;quot;&amp;quot; . $struct[$attr] .'&amp;quot; ';&lt;br /&gt;
                    unset($struct[$attr]);&lt;br /&gt;
                    }&lt;br /&gt;
            $s .= &amp;quot;&amp;gt;&amp;quot; . makeXOXO($text) .&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
            unset($struct['url'],$struct['text']);&lt;br /&gt;
            }&lt;br /&gt;
        if (count($struct))&lt;br /&gt;
            {&lt;br /&gt;
            $s .=&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
            foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
                $s .= &amp;quot;&amp;lt;dt&amp;gt;$key&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;quot;. makeXOXO($value) . &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;;&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    else&lt;br /&gt;
        $s .= &amp;quot;$struct&amp;quot;;&lt;br /&gt;
    #echo &amp;quot;returned $s\n&amp;quot;;&lt;br /&gt;
    return $s;&lt;br /&gt;
}&lt;br /&gt;
function toXOXO($struct,$addHTMLWrapper=FALSE,$cssUrl='')&lt;br /&gt;
{&lt;br /&gt;
    if (getKind($struct) != 'list')&lt;br /&gt;
        $struct = array($struct);&lt;br /&gt;
    $xoxo = makeXOXO($struct,'xoxo');&lt;br /&gt;
    if ($addHTMLWrapper)&lt;br /&gt;
        {&lt;br /&gt;
        $s= '&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;';&lt;br /&gt;
        if ($cssUrl) $s .=&amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot; &amp;gt;@import \&amp;quot;$cssUrl\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;$xoxo&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
        return $s;&lt;br /&gt;
        }&lt;br /&gt;
    return $xoxo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function pushStruct($struct,&amp;amp;$structstack,&amp;amp;$xostack,$structType)&lt;br /&gt;
{&lt;br /&gt;
    if (is_array($struct) &amp;amp;&amp;amp; $structType=='dict' &amp;amp;&amp;amp; count($structstack) &amp;amp;&amp;amp; is_array(end($structstack)) &amp;amp;&amp;amp; isset($structstack[count($structstack)-1]['url']) &amp;amp;&amp;amp; end($structstack) != end($xostack))&lt;br /&gt;
        $xostack[] = &amp;amp;$structstack[count($structstack)-1]; # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
    else&lt;br /&gt;
        {&lt;br /&gt;
        $structstack[]=$struct;&lt;br /&gt;
        $xostack[]=&amp;amp;$structstack[count($structstack)-1];&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fromXOXO($html)&lt;br /&gt;
{&lt;br /&gt;
    $structs=array();&lt;br /&gt;
    $xostack=array();&lt;br /&gt;
    $textstack=array('');&lt;br /&gt;
    $dumpStacks=0;&lt;br /&gt;
    $p = xml_parser_create();&lt;br /&gt;
    xml_parse_into_struct($p, $html, $xoxoVals, $xoxoIndex);&lt;br /&gt;
    xml_parser_free($p);&lt;br /&gt;
&lt;br /&gt;
  if($dumpStacks)&lt;br /&gt;
        {&lt;br /&gt;
        echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
        var_dump($xoxoVals);&lt;br /&gt;
        var_dump($xoxoIndex);&lt;br /&gt;
        echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;; &lt;br /&gt;
        }&lt;br /&gt;
    $howmany = sizeof($xoxoVals);&lt;br /&gt;
    &lt;br /&gt;
    #echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    $x = $xoxoIndex['OL'];&lt;br /&gt;
    for ($x=0;$x&amp;lt;$howmany;++$x)&lt;br /&gt;
        {&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'OL' || $xoxoVals[$x]['tag'] == 'DL'|| $xoxoVals[$x]['tag'] == 'UL')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['tag'] == 'DL')&lt;br /&gt;
                $structType = 'dict';&lt;br /&gt;
            else &lt;br /&gt;
                $structType = 'list';&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'open')&lt;br /&gt;
                pushStruct(array(),$structs,$xostack,$structType);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'LI')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
               array_push($xostack[count($xostack)-1],$xoxoVals[$x]['value']);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                array_push($xostack[count($xostack)-1],array_pop($structs));&lt;br /&gt;
                }&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DT')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                array_push($textstack,$xoxoVals[$x]['value']);&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DD')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] = $xoxoVals[$x]['value'];&lt;br /&gt;
                }&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] =array_pop($structs);&lt;br /&gt;
                }&lt;br /&gt;
          if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'A')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $attrs = $xoxoVals[$x]['attributes'];&lt;br /&gt;
                $dict=array();&lt;br /&gt;
                foreach ($attrs as $key=&amp;gt; $value)&lt;br /&gt;
                    {&lt;br /&gt;
                    if ($key=='HREF')&lt;br /&gt;
                        $dict['url'] = $value;&lt;br /&gt;
                    else&lt;br /&gt;
                        $dict[strtolower($key)] = $value;&lt;br /&gt;
                    }&lt;br /&gt;
                $val = $xoxoVals[$x]['value'];&lt;br /&gt;
                if (isset($val) &amp;amp;&amp;amp; ($val != $dict['title']) &amp;amp;&amp;amp; ($val != $dict['url']))&lt;br /&gt;
                    $dict['text'] = $val;&lt;br /&gt;
                pushStruct($dict,$structs,$xostack,'dict');&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
 &lt;br /&gt;
                if($dumpStacks)&lt;br /&gt;
                    {&lt;br /&gt;
                    echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                    var_dump($structs);&lt;br /&gt;
                    var_dump($xostack);&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
     #echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;;&lt;br /&gt;
   while (count($structs) == 1 &amp;amp;&amp;amp; getKind($structs) == 'list')&lt;br /&gt;
        $structs = $structs[0];&lt;br /&gt;
    return $structs;&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== xoxotest.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
include(&amp;quot;xoxolib.php&amp;quot;);&lt;br /&gt;
function assertEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 == $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str2&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function assertArrayEqual($testname,$expected,$returned)&lt;br /&gt;
{&lt;br /&gt;
if ($expected == $returned)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($expected);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($returned);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function failIfEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 != $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;both were&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$l = array('1','2','3');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$s = 'test';&lt;br /&gt;
$html = toXOXO($s);&lt;br /&gt;
assertEqual(&amp;quot;make xoxo from a string&amp;quot;,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$htmlwrap = toXOXO($s,TRUE);&lt;br /&gt;
failIfEqual(&amp;quot;make sure wrapped and unwrapped differ&amp;quot;,html,htmlwrap);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$htmlwrap);&lt;br /&gt;
$csswrap = toXOXO($s,TRUE,&amp;quot;reaptest.css&amp;quot;);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo with css link from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$csswrap);&lt;br /&gt;
$l2 = array('1',array('2','3'));&lt;br /&gt;
$html = toXOXO($l2);&lt;br /&gt;
assertEqual('make xoxo from nested list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from 1-element dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','thing'=&amp;gt;'and another thing...');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and thing','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;thing&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;and another thing...&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','list'=&amp;gt;array('and', 'another','thing...'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;list&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;and&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;another&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;thing...&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from dict in list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;a&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;2&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$l = array('3','2','1');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list to xoxo and back',$l,$newdl);&lt;br /&gt;
$l = array('1',array('a','b'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
&lt;br /&gt;
$l= array('3',array('a','2'),array('b',array('1',array('c','4'))));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'),array('b'=&amp;gt;'1','c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('list of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'two'=&amp;gt;array('c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'url'=&amp;gt;'http://example.com');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts with url to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts with url to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$d = array('test'=&amp;gt; array('1','2'),&lt;br /&gt;
'name'=&amp;gt; 'Kevin','nestlist'=&amp;gt; array('a',array('b','c')),&lt;br /&gt;
'nestdict'=&amp;gt;array('e'=&amp;gt;'6','f'=&amp;gt;'7'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary of lists  to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$d=fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text outside &amp;amp;lt;li&amp;amp;gt; etc is ignored',array(good=&amp;gt;buy),$d);&lt;br /&gt;
&lt;br /&gt;
$l=fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text within &amp;amp;lt;li&amp;amp;gt; but outside a subcontainer is ignored',array(array(good=&amp;gt;buy),array('OK')),$l);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$d2=array('text'=&amp;gt;'item 1',&lt;br /&gt;
    'description'=&amp;gt;&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
    'url'=&amp;gt;'http://example.com/more.xoxo',&lt;br /&gt;
    'title'=&amp;gt;'title of item 1',&lt;br /&gt;
    'type'=&amp;gt;'text/xml',&lt;br /&gt;
    'rel'=&amp;gt;'help');&lt;br /&gt;
assertArrayEqual('unmung some xoxo with spaces in and check result is right',$d2,$d);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (no text)',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (just url)',$d,fromXOXO($html));&lt;br /&gt;
$kmattn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
$d=fromXOXO($kmattn);&lt;br /&gt;
$newattn = toXOXO($d);&lt;br /&gt;
$d2=fromXOXO($newattn);&lt;br /&gt;
assertArrayEqual('attention double round-trip',$d,$d2);&lt;br /&gt;
assertEqual('attention triple round-trip',$newattn,toXOXO($d2));&lt;br /&gt;
assertEqual('attention one round-trip',$kmattn,$newattn);&lt;br /&gt;
$d=array(array(url=&amp;gt;&amp;quot;http://www.boingboing.net/&amp;quot;,title=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://boingboing.net/rss.xml&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;),array(url=&amp;gt;&amp;quot;http://www.financialcryptography.com/&amp;quot;,title=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;));&lt;br /&gt;
$attn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
assertEqual('attention encode',$attn,toXOXO($d));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
== autres implémentations ==&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/xoxo2array.php.txt xoxo2array.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/array2xoxo.php.txt array2xoxo.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/#outlineclasses Outline Classes]&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-java&amp;diff=41706</id>
		<title>xoxo-sample-code-java</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-java&amp;diff=41706"/>
		<updated>2010-01-27T18:07:01Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Sample Code - Java =&lt;br /&gt;
:'''this is  sub-page of [[xoxo-sample-code]]'''&lt;br /&gt;
&lt;br /&gt;
== XOXOWriter.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOWriter {&lt;br /&gt;
&lt;br /&gt;
  public String[] attrs = {&amp;quot;title&amp;quot;,&amp;quot;rel&amp;quot;,&amp;quot;type&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className){&lt;br /&gt;
    return makeXOXO(struct, className, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className,&lt;br /&gt;
                         boolean doNSDeclaration){&lt;br /&gt;
    return makeXOXO(struct, className, 0, doNSDeclaration);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct){&lt;br /&gt;
    return makeXOXO(struct, &amp;quot;xoxo&amp;quot;, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, int depth){&lt;br /&gt;
    return makeXOXO(struct, null, 0, false);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, String className,&lt;br /&gt;
                         int depth, boolean doNSDeclaration){&lt;br /&gt;
    if(struct == null) return &amp;quot;&amp;quot;;&lt;br /&gt;
    StringBuffer sb = new StringBuffer();&lt;br /&gt;
    if(struct instanceof Object[]){&lt;br /&gt;
      struct = Arrays.asList((Object[]) struct);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof List){&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;ol&amp;quot;);&lt;br /&gt;
      if(doNSDeclaration)&lt;br /&gt;
        sb.append(&amp;quot; xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;quot;);&lt;br /&gt;
      if(className != null){&lt;br /&gt;
        sb.append(&amp;quot; class=\&amp;quot;&amp;quot;);&lt;br /&gt;
        sb.append(className);&lt;br /&gt;
        sb.append(&amp;quot;\&amp;quot;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof Map){&lt;br /&gt;
      Map d = new LinkedHashMap((Map) struct);&lt;br /&gt;
      if(d.containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;a href=\&amp;quot;&amp;quot; + d.get(&amp;quot;url&amp;quot;) + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
        Object text;&lt;br /&gt;
        if(d.containsKey(&amp;quot;text&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;text&amp;quot;);&lt;br /&gt;
        }else if(d.containsKey(&amp;quot;title&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
          text = d.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        for(int i=0; i&amp;lt;attrs.length; i++){&lt;br /&gt;
          String xVal = makeXOXO(d.get(attrs[i]),depth+1);&lt;br /&gt;
          if(xVal != null &amp;amp;&amp;amp; !xVal.equals(&amp;quot;&amp;quot;)){&lt;br /&gt;
            sb.append(attrs[i] + &amp;quot;=\&amp;quot;&amp;quot; + xVal + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
          d.remove(attrs[i]);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;gt;&amp;quot; + makeXOXO(text, depth+1) + &amp;quot;&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;text&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;url&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      if(!d.isEmpty()){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;);&lt;br /&gt;
        for(Iterator i = d.entrySet().iterator(); i.hasNext();){&lt;br /&gt;
          Map.Entry entry = (Map.Entry)i.next();&lt;br /&gt;
          String ddVal = makeXOXO(entry.getValue(),depth+1);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dt&amp;gt;&amp;quot; + entry.getKey() + &amp;quot;&amp;lt;/dt&amp;gt;&amp;quot;);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dd&amp;gt;&amp;quot; + ddVal + &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
    }else if(struct instanceof List){&lt;br /&gt;
      List l = (List) struct;&lt;br /&gt;
      for(Iterator i = l.iterator(); i.hasNext();){&lt;br /&gt;
        Object item = i.next();&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,depth+1) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);&lt;br /&gt;
    }else{&lt;br /&gt;
      sb.append(struct);&lt;br /&gt;
    }&lt;br /&gt;
    return sb.toString();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct){&lt;br /&gt;
    return toXOXO(struct, false, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist, addHTMLWrapper, cssUrl);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;quot;;&lt;br /&gt;
    if(addHTMLWrapper){&lt;br /&gt;
      String s = startHTML;&lt;br /&gt;
      if(cssUrl != null){&lt;br /&gt;
        s += &amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot;&amp;gt;@import \&amp;quot;&amp;quot;&lt;br /&gt;
            + cssUrl + &amp;quot;\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      s += &amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot; + makeXOXO(struct, &amp;quot;xoxo&amp;quot;, false)&lt;br /&gt;
          + &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
      return s;&lt;br /&gt;
    }else{&lt;br /&gt;
      return makeXOXO(struct, &amp;quot;xoxo&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOParser.java ==&lt;br /&gt;
This needs some small additions to handle the XHTML DTD and named character entities.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import org.xml.sax.InputSource;&lt;br /&gt;
import org.xml.sax.SAXException;&lt;br /&gt;
import org.xml.sax.XMLReader;&lt;br /&gt;
import org.xml.sax.Attributes;&lt;br /&gt;
import org.xml.sax.helpers.XMLReaderFactory;&lt;br /&gt;
import org.xml.sax.helpers.DefaultHandler;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
import java.io.InputStream;&lt;br /&gt;
import java.io.StringReader;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
&lt;br /&gt;
public class XOXOParser extends DefaultHandler {&lt;br /&gt;
&lt;br /&gt;
  protected String XHTML_NS = &amp;quot;http://www.w3.org/1999/xhtml&amp;quot;;&lt;br /&gt;
  protected List elStack;&lt;br /&gt;
  protected Map listEls;&lt;br /&gt;
  public List structs;&lt;br /&gt;
  public List xoStack;&lt;br /&gt;
  public List textStack;&lt;br /&gt;
&lt;br /&gt;
  public XOXOParser() {&lt;br /&gt;
    reset();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void pushStruct(Object struct){&lt;br /&gt;
    if(struct instanceof Map &amp;amp;&amp;amp; !((Map) struct).isEmpty()&lt;br /&gt;
        &amp;amp;&amp;amp; structs.get(structs.size()-1) instanceof Map&lt;br /&gt;
        &amp;amp;&amp;amp; ((Map) struct).containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
      // put back the &amp;lt;a&amp;gt;-made one for extra defs&lt;br /&gt;
      xoStack.add(structs.get(structs.size()-1));&lt;br /&gt;
    }else{&lt;br /&gt;
      structs.add(struct);&lt;br /&gt;
      xoStack.add(struct);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void startElement(String nsUri, String localName,&lt;br /&gt;
                           String qName, Attributes atts){&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri.equals(XHTML_NS)){&lt;br /&gt;
      elStack.add(localName);&lt;br /&gt;
    }else{&lt;br /&gt;
      elStack.add(&amp;quot;foo&amp;quot;);&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      Map attmap = new LinkedHashMap();&lt;br /&gt;
      int len = atts.getLength();&lt;br /&gt;
      for(int i=0; i&amp;lt;len; i++){&lt;br /&gt;
        attmap.put(atts.getQName(i),atts.getValue(i));&lt;br /&gt;
      }&lt;br /&gt;
      if(attmap.containsKey(&amp;quot;href&amp;quot;)){&lt;br /&gt;
        attmap.put(&amp;quot;url&amp;quot;,attmap.get(&amp;quot;href&amp;quot;));&lt;br /&gt;
        attmap.remove(&amp;quot;href&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      pushStruct(attmap);&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      pushStruct(new LinkedHashMap());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dt&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void endElement(String nsUri, String localName,&lt;br /&gt;
                         String qName){&lt;br /&gt;
    elStack.remove(elStack.size()-1);&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri != XHTML_NS){&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      String val = (String) textStack.remove(textStack.size()-1);&lt;br /&gt;
      if (val.length() &amp;gt; 0){&lt;br /&gt;
        Map defs = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
        String defVal = (String) defs.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        if(defVal != null &amp;amp;&amp;amp; val.equals(defVal)){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        defVal = (String) defs.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        if(defVal != null &amp;amp;&amp;amp; val.equals(defVal)){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        if(val.length() &amp;gt; 0){&lt;br /&gt;
          defs.put(&amp;quot;text&amp;quot;,val);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      List last = (List) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.add(val);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Object key = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Map last = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.put(key,val);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void characters(char[] ch, int start, int length){&lt;br /&gt;
    if(!xoStack.isEmpty()&lt;br /&gt;
        &amp;amp;&amp;amp; !listEls.containsKey(elStack.get(elStack.size()-1))){&lt;br /&gt;
      String text = (String) textStack.get(textStack.size()-1);&lt;br /&gt;
      String test = new String(ch,start,length);&lt;br /&gt;
      textStack.set(textStack.size()-1,text+test);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(String s) throws SAXException, IOException{&lt;br /&gt;
    return parse(new InputSource(new StringReader(s)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputStream is) throws SAXException, IOException {&lt;br /&gt;
    return parse(new InputSource(is));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputSource in) throws SAXException, IOException {&lt;br /&gt;
    XMLReader parser = XMLReaderFactory.createXMLReader();&lt;br /&gt;
    parser.setContentHandler(this);&lt;br /&gt;
    parser.parse(in);&lt;br /&gt;
    List returnList = new ArrayList();&lt;br /&gt;
    for(Iterator i = this.structs.iterator(); i.hasNext();){&lt;br /&gt;
      Object thing = i.next();&lt;br /&gt;
      if(thing != null){&lt;br /&gt;
        returnList.add(thing);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    while(returnList.size()==1){&lt;br /&gt;
      if(returnList.get(0) instanceof List){&lt;br /&gt;
        returnList = (List) returnList.get(0);&lt;br /&gt;
      }else{&lt;br /&gt;
        reset();&lt;br /&gt;
        return returnList.get(0);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    reset();&lt;br /&gt;
    return returnList;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void reset(){&lt;br /&gt;
    elStack = new ArrayList();&lt;br /&gt;
    listEls = new HashMap();&lt;br /&gt;
    structs = new ArrayList();&lt;br /&gt;
    xoStack = new ArrayList();&lt;br /&gt;
    textStack = new ArrayList();&lt;br /&gt;
    listEls.put(&amp;quot;ol&amp;quot;,&amp;quot;ol&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;ul&amp;quot;,&amp;quot;ul&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;dl&amp;quot;,&amp;quot;dl&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOTest.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo.tests;&lt;br /&gt;
&lt;br /&gt;
import junit.framework.TestSuite;&lt;br /&gt;
import junit.framework.TestCase;&lt;br /&gt;
import junit.textui.TestRunner;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOWriter;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOParser;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOTest extends TestCase {&lt;br /&gt;
&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    new TestRunner().doRun(new TestSuite(XOXOTest.class));&lt;br /&gt;
  }&lt;br /&gt;
  String XHTML_DEC = &amp;quot;xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot; &amp;quot;;&lt;br /&gt;
  public String simpleListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSimpleList(){&lt;br /&gt;
    String [] numbers = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testStringIntegerList(){&lt;br /&gt;
    Object[] numbers = {new Integer(1),&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String nestedListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testNestedList(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,Arrays.asList(arr)};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testNestedArray(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,arr};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String dictHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testDictionary(){&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, new Integer(1));&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(dictHTML,&lt;br /&gt;
                 xoxo.toXOXO(dict));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String singleHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(singleHTML,&lt;br /&gt;
                 xoxo.toXOXO(item));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testWrapDiffers(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String nowrap = xoxo.toXOXO(item);&lt;br /&gt;
    Object[] itemArr = {item};&lt;br /&gt;
    String wrap = xoxo.toXOXO(Arrays.asList(itemArr),true,null);&lt;br /&gt;
    assertFalse(wrap.equals(nowrap));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;;&lt;br /&gt;
  public String singleWrapHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
  public String endHTML = &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testWrapSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(startHTML + singleWrapHTML + endHTML,&lt;br /&gt;
                 xoxo.toXOXO(item,true,null));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOParser(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      parser.parse(dictHTML);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
     try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListRoundTrip(){&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfDictsRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    Map dict2 = new LinkedHashMap();&lt;br /&gt;
    dict2.put(&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;three&amp;quot;, &amp;quot;four&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;five&amp;quot;, &amp;quot;six&amp;quot;);&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,dict,dict2};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;, Arrays.asList(list1)};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;, Arrays.asList(list2)};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, Arrays.asList(list3)};&lt;br /&gt;
    List testList = Arrays.asList(list4);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, &amp;quot;9&amp;quot;};&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;foo&amp;quot;, Arrays.asList(list1));&lt;br /&gt;
    dict.put(&amp;quot;bar&amp;quot;, Arrays.asList(list2));&lt;br /&gt;
    dict.put(&amp;quot;baz&amp;quot;, Arrays.asList(list3));&lt;br /&gt;
    dict.put(&amp;quot;qux&amp;quot;, Arrays.asList(list4));&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOJunkInContainers(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(junkXOXO);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkElementXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOjunkInElements(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    Object[] ok = {&amp;quot;OK&amp;quot;};&lt;br /&gt;
    Object[] obj ={dict, Arrays.asList(ok)};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(junkElementXOXO);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSpacesNewlines = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt; This item represents the main&amp;quot; +&lt;br /&gt;
      &amp;quot; point we're trying to make.&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOWithSpacesAndNewlines(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;description&amp;quot;,&amp;quot; This item represents the main&amp;quot; +&lt;br /&gt;
        &amp;quot; point we're trying to make.&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;title of item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(xoxoSpacesNewlines);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSample = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public String smartXOXOSample = &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         title=\&amp;quot;title of item 1\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         type=\&amp;quot;text/xml\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply&amp;quot; +&lt;br /&gt;
      &amp;quot; the contents of the &amp;lt;a&amp;gt; element --&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeDecoding(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object xoxoDict = parser.parse(xoxoSample);&lt;br /&gt;
      Object xoxoDict2 = parser.parse(smartXOXOSample);&lt;br /&gt;
      assertEquals(xoxoDict,xoxoDict2);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String specialAttrHTML =  &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot; title=\&amp;quot;sample url\&amp;quot; &amp;quot; +&lt;br /&gt;
      &amp;quot;rel=\&amp;quot;help\&amp;quot; type=\&amp;quot;text/xml\&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeEncode(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    assertEquals(specialAttrHTML,html);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripFull(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoText(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoTextOrTitle(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testUnicodeRoundTrip(){&lt;br /&gt;
    String s = &amp;quot;Tantek Çelik and a snowman ?&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(s);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newString = parser.parse(html);&lt;br /&gt;
      assertEquals(s,newString);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=41704</id>
		<title>xoxo-sample-code-fr</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-fr&amp;diff=41704"/>
		<updated>2010-01-26T01:15:33Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Code Echantillon =&lt;br /&gt;
&lt;br /&gt;
Un paquet général de code échantillon open source, ([http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0]) pour lire et écrire des fichiers [[xoxo-fr|xoxo]] en Python et Java (avec Perl, PHP, ... à suivre).&lt;br /&gt;
= Python =&lt;br /&gt;
== xoxo.py ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;xoxo.py - a utility module for transforming to and from the XHTMLOutlines format XOXO http://microformats.org/wiki/xoxo&lt;br /&gt;
toXOXO takes a Python datastructure (tuples, lists or dictionaries, arbitrarily nested) and returns a XOXO representation of it.&lt;br /&gt;
fromXOXO parses an XHTML file for a xoxo list and returns the structure&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__version__ = &amp;quot;0.9&amp;quot;&lt;br /&gt;
__date__ = &amp;quot;2005-11-02&amp;quot;&lt;br /&gt;
__author__ = &amp;quot;Kevin Marks &amp;lt;kmarks@technorati.com&amp;gt;&amp;quot;&lt;br /&gt;
__copyright__ = &amp;quot;Copyright 2004-2006, Kevin Marks &amp;amp; Technorati&amp;quot;&lt;br /&gt;
__license__ = &amp;quot;http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0&amp;quot;&lt;br /&gt;
__credits__ = &amp;quot;&amp;quot;&amp;quot;Tantek Çelik and Mark Pilgrim for data structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__history__ = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
TODO: add &amp;lt;title&amp;gt; tag&lt;br /&gt;
TODO: add a proper profile link&lt;br /&gt;
0.9 smarter parsing for encoding and partial markup; fix dangling dictionary case&lt;br /&gt;
0.8 work in unicode then render to utf-8&lt;br /&gt;
0.7 initial encoding support - just utf-8 for now&lt;br /&gt;
0.6 support the special behavior for url properties  to/from &amp;lt;a&amp;gt;&lt;br /&gt;
0.5 fix some awkward side effects of whitespace and text outside our expected tags; simplify writing code&lt;br /&gt;
0.4 add correct XHTML headers so it validates&lt;br /&gt;
0.3 read/write version; fixed invalid nested list generation;&lt;br /&gt;
0.1 first write-only version&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    True, False&lt;br /&gt;
except NameError:&lt;br /&gt;
    True, False = not not 1, not 1&lt;br /&gt;
containerTags={'ol':False,'ul':False,'dl':False}&lt;br /&gt;
import sgmllib, urllib, urlparse, re,codecs&lt;br /&gt;
&lt;br /&gt;
def toUnicode(key):&lt;br /&gt;
    if type(key) == type(u'unicode'):&lt;br /&gt;
        uKey= key&lt;br /&gt;
    else:&lt;br /&gt;
        try: &lt;br /&gt;
            uKey=unicode(key,'utf-8')&lt;br /&gt;
        except:&lt;br /&gt;
            uKey=unicode(key,'windows_1252')&lt;br /&gt;
    return uKey&lt;br /&gt;
&lt;br /&gt;
def makeXOXO(struct,className=None):&lt;br /&gt;
    s=u''&lt;br /&gt;
    if isinstance(struct,list) or isinstance(struct,tuple):&lt;br /&gt;
        if className:&lt;br /&gt;
            s += u'&amp;lt;ol class=&amp;quot;%s&amp;quot;&amp;gt;' % className&lt;br /&gt;
        else:&lt;br /&gt;
            s+= u&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;&lt;br /&gt;
        for item in struct:&lt;br /&gt;
            s+=u&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,None)+&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
        s +=u&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;br /&gt;
    elif isinstance(struct,dict):&lt;br /&gt;
        d=struct.copy()&lt;br /&gt;
        if 'url' in d:&lt;br /&gt;
            uURL=toUnicode(d['url'])&lt;br /&gt;
            s+=u'&amp;lt;a href=&amp;quot;%s&amp;quot; ' % uURL&lt;br /&gt;
            text =  d.get('text',d.get('title',uURL))&lt;br /&gt;
            for attr in ('title','rel','type'):&lt;br /&gt;
                if attr in d:&lt;br /&gt;
                    xVal = makeXOXO(d[attr],None)&lt;br /&gt;
                    s +=u'%s=&amp;quot;%s&amp;quot; ' % (attr,xVal)&lt;br /&gt;
                    del d[attr]&lt;br /&gt;
            s +=u'&amp;gt;%s&amp;lt;/a&amp;gt;' % makeXOXO(text,None)&lt;br /&gt;
            if 'text' in d:&lt;br /&gt;
                del d['text']&lt;br /&gt;
            del d['url']&lt;br /&gt;
        if len(d):&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;&lt;br /&gt;
            for key,value in d.items():&lt;br /&gt;
                xVal = makeXOXO(value,None)&lt;br /&gt;
                uKey=toUnicode(key)&lt;br /&gt;
                s+= u'&amp;lt;dt&amp;gt;%s&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;%s&amp;lt;/dd&amp;gt;' % (uKey, xVal)&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
    elif type(struct) == type(u'unicode'):&lt;br /&gt;
        s+=struct&lt;br /&gt;
    else:&lt;br /&gt;
        if type(struct)!=type(' '):&lt;br /&gt;
            struct=str(struct)&lt;br /&gt;
        s += toUnicode(struct)&lt;br /&gt;
    return s&lt;br /&gt;
class AttrParser(sgmllib.SGMLParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        sgmllib.SGMLParser.__init__(self)&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.encoding='utf-8'&lt;br /&gt;
    def cleanText(self,inText):&lt;br /&gt;
        if type(inText) == type(u'unicode'):&lt;br /&gt;
            inText = inText.encode(self.encoding,'replace')&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.reset()&lt;br /&gt;
        self.feed(inText)&lt;br /&gt;
        return ''.join(self.text)&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        if 'ascii' in encoding:&lt;br /&gt;
            encoding='windows_1252' # so we don't throw an exception on high-bit set chars in there by mistake&lt;br /&gt;
        if encoding and not encoding =='text/html':&lt;br /&gt;
            try:&lt;br /&gt;
                canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                self.encoding = encoding&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    encoding='japanese.' +encoding&lt;br /&gt;
                    canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                    self.encoding = encoding&lt;br /&gt;
                except:&lt;br /&gt;
                    print &amp;quot;can't deal with encoding %s&amp;quot; % encoding&lt;br /&gt;
                    &lt;br /&gt;
    def handle_entityref(self, ref):&lt;br /&gt;
        # called for each entity reference, e.g. for &amp;quot;&amp;amp;copy;&amp;quot;, ref will be &amp;quot;copy&amp;quot;&lt;br /&gt;
        # map through to unicode where we can&lt;br /&gt;
        try:&lt;br /&gt;
            entity =htmlentitydefs.name2codepoint[ref]&lt;br /&gt;
            self.handleUnicodeData(unichr(entity))&lt;br /&gt;
        except:&lt;br /&gt;
            try:&lt;br /&gt;
                handle_charref(ref) # deal with char-ref's missing the '#' (see Akma)&lt;br /&gt;
            except:&lt;br /&gt;
                self.handle_data(&amp;quot;&amp;amp;%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
    def handle_charref(self, ref):&lt;br /&gt;
        # called for each character reference, e.g. for &amp;quot;&amp;amp;#160;&amp;quot;, ref will be &amp;quot;160&amp;quot;&lt;br /&gt;
        # Reconstruct the original character reference.&lt;br /&gt;
        try:&lt;br /&gt;
            if ref[0]=='x':&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref[1:],16)))&lt;br /&gt;
            else:&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref)))&lt;br /&gt;
        except:&lt;br /&gt;
            self.handle_data(&amp;quot;&amp;amp;#%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
# called for each block of plain text, i.e. outside of any tag and&lt;br /&gt;
# not containing any character or entity references&lt;br /&gt;
    def handle_data(self, text):&lt;br /&gt;
        if type(text)==type(u' '):&lt;br /&gt;
            self.handleUnicodeData(text)&lt;br /&gt;
        if self.encoding== 'utf-8':&lt;br /&gt;
            try:&lt;br /&gt;
                uText = unicode(text,self.encoding) #utf-8 is pretty clear when it is wrong&lt;br /&gt;
            except:&lt;br /&gt;
                uText = unicode(text,'windows_1252','ignore') # and this is the likely wrongness&lt;br /&gt;
        else:&lt;br /&gt;
            uText = unicode(text,self.encoding,'replace') # if they have really broken encoding, (eg lots of shift-JIS blogs)&lt;br /&gt;
        self.handleUnicodeData(uText)&lt;br /&gt;
    def handleUnicodeData(self, uText):&lt;br /&gt;
        self.text.append(uText)&lt;br /&gt;
        &lt;br /&gt;
class xoxoParser(AttrParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        AttrParser.__init__(self)&lt;br /&gt;
        self.structs=[]&lt;br /&gt;
        self.xostack=[]&lt;br /&gt;
        self.textstack=['']&lt;br /&gt;
        self.attrparse = AttrParser()&lt;br /&gt;
    def normalize_attrs(self, attrs):&lt;br /&gt;
        attrs = [(k.lower(), self.attrparse.cleanText(v)) for k, v in attrs]&lt;br /&gt;
        attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs]&lt;br /&gt;
        return attrs&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        AttrParser.setEncoding(self,encoding)&lt;br /&gt;
        self.attrparse.setEncoding(encoding)&lt;br /&gt;
    def pushStruct(self,struct):&lt;br /&gt;
        if type(struct) == type({}) and len(struct)==0 and len(self.structs) and type(self.structs[-1]) == type({}) and 'url' in self.structs[-1] and self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            self.xostack.append(self.structs[-1]) # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
        else:&lt;br /&gt;
            self.structs.append(struct)&lt;br /&gt;
            self.xostack.append(self.structs[-1])&lt;br /&gt;
    def do_meta(self, attributes):&lt;br /&gt;
        atts = dict(self.normalize_attrs(attributes))&lt;br /&gt;
        #print atts.encode('utf-8')&lt;br /&gt;
        if 'http-equiv' in atts:&lt;br /&gt;
            if atts['http-equiv'].lower() == &amp;quot;content-type&amp;quot;:&lt;br /&gt;
                if 'content' in atts:&lt;br /&gt;
                    encoding = atts['content'].split('charset=')[-1]&lt;br /&gt;
                    self.setEncoding(encoding)&lt;br /&gt;
    def start_a(self,attrs):&lt;br /&gt;
        attrsD = dict(self.normalize_attrs(attrs))&lt;br /&gt;
        attrsD['url']= attrsD.get('href','')&lt;br /&gt;
        if 'href' in attrsD:&lt;br /&gt;
            del attrsD['href']&lt;br /&gt;
        self.pushStruct(attrsD)&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_a(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        if val: &lt;br /&gt;
            if self.xostack[-1].get('title','') == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if self.xostack[-1]['url'] == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if val:&lt;br /&gt;
                self.xostack[-1]['text']=val&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_dl(self,attrs):&lt;br /&gt;
        self.pushStruct({})&lt;br /&gt;
    def end_dl(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ol(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ol(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ul(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ul(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_li(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_li(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        while self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
        if type(val) == type(' ') or type(val) == type(u' '):&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
    def start_dt(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dt(self):&lt;br /&gt;
        pass&lt;br /&gt;
    def start_dd(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dd(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        key = self.textstack.pop()&lt;br /&gt;
        if self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
        self.xostack[-1][key]=val&lt;br /&gt;
    def handleUnicodeData(self, text):&lt;br /&gt;
        if len(self.stack) and containerTags.get(self.stack[-1],True): #skip text not within an element&lt;br /&gt;
            self.textstack[-1] += text&lt;br /&gt;
def toXOXO(struct,addHTMLWrapper=False,cssUrl=''):&lt;br /&gt;
    if type(struct) ==type((1,))or type(struct) ==type([1,]):&lt;br /&gt;
        inStruct = struct&lt;br /&gt;
    else:&lt;br /&gt;
        inStruct = [struct]&lt;br /&gt;
    if addHTMLWrapper:&lt;br /&gt;
        s= u'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;'''&lt;br /&gt;
        if cssUrl:&lt;br /&gt;
            s+=u'&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;%s&amp;quot;;&amp;lt;/style&amp;gt;' % cssUrl&lt;br /&gt;
        s+=u&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot; % makeXOXO(inStruct,'xoxo')&lt;br /&gt;
        return s.encode('utf-8')&lt;br /&gt;
    else:&lt;br /&gt;
        return makeXOXO(inStruct,'xoxo').encode('utf-8')&lt;br /&gt;
    &lt;br /&gt;
def fromXOXO(html):&lt;br /&gt;
    parser = xoxoParser()&lt;br /&gt;
    #parser.feed(unicode(html,'utf-8'))&lt;br /&gt;
    parser.feed(html)&lt;br /&gt;
    #print parser.structs&lt;br /&gt;
    structs=[struct for struct in parser.structs if struct]&lt;br /&gt;
    #print structs&lt;br /&gt;
    while len(structs) ==1 and type(structs)==type([1,]):&lt;br /&gt;
        structs=structs[0]&lt;br /&gt;
    return structs&lt;br /&gt;
&lt;br /&gt;
# Allow direct invocation&lt;br /&gt;
# Read HTML from URL, parse into data structures, then re-output&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  if len(sys.argv) &amp;lt; 2: raise SystemExit(&amp;quot;Usage: &amp;quot;+sys.argv[0]+&amp;quot; url\n&amp;quot;+__doc__)&lt;br /&gt;
  url=sys.argv[1]&lt;br /&gt;
  file = urllib.urlopen(url)&lt;br /&gt;
  html=file.read(-1)&lt;br /&gt;
  file.close&lt;br /&gt;
  s=fromXOXO(html)&lt;br /&gt;
  p=toXOXO(s,True)&lt;br /&gt;
  print p&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== testxoxo.py  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;testxoxo.py &lt;br /&gt;
Unit tests for xoxo.py&lt;br /&gt;
This file tests the functions in xoxo.py &lt;br /&gt;
The underlying model here is http://diveintopython.org/unit_testing/index.html &lt;br /&gt;
&lt;br /&gt;
run from command line with&lt;br /&gt;
python testxoxo.py -v&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import xoxo&lt;br /&gt;
reload(xoxo)&lt;br /&gt;
import unittest&lt;br /&gt;
&lt;br /&gt;
class xoxoTestCases(unittest.TestCase):&lt;br /&gt;
    &lt;br /&gt;
    def testSimpleList(self):&lt;br /&gt;
        '''make a xoxo file from a list'''&lt;br /&gt;
        l = ['1','2','3']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
    def testNestedList(self):&lt;br /&gt;
        '''make a xoxo file from a list with a list in'''&lt;br /&gt;
        l = ['1',['2','3']]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testDictionary(self):&lt;br /&gt;
        '''make a xoxo file from a dictionary'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testSingleItem(self):&lt;br /&gt;
        '''make a xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testWrapDiffers(self):&lt;br /&gt;
        '''make a xoxo file from a string with and without html wrapper and check they are different'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        htmlwrap =  xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.failIfEqual(html,htmlwrap)&lt;br /&gt;
&lt;br /&gt;
    def testWrapSingleItem(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testWrapItemWithCSS(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True,cssUrl='reaptest.css')&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
        &lt;br /&gt;
    def testDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary wiht an url in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)    &lt;br /&gt;
    def testNestedDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with a dict in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionariesWithURLsRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict with an url into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin','url':'http://slashdot.org'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testListRoundTrip(self):&lt;br /&gt;
        ''' make a list into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3','2','1']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofDictsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Dicts into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',{'a':'2'},{'b':'1','c':'4'}]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofListsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Lists into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',['a','2'],['b',['1',['c','4']]]]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testDictofListsRoundTrip(self):&lt;br /&gt;
        ''' make a dict with lists in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':['1','2'],&lt;br /&gt;
        'name':'Kevin',&lt;br /&gt;
        'nestlist':['a',['b','c']],&lt;br /&gt;
        'nestdict':{'e':'6','f':'7'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInContainers(self):&lt;br /&gt;
        '''make sure text outside &amp;lt;li&amp;gt; etc is ignored'''&lt;br /&gt;
        d=xoxo.fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(d,{'good': 'buy'})&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInElements(self):&lt;br /&gt;
        '''make sure text within &amp;lt;li&amp;gt; but outside a subcontainer is ignored'''&lt;br /&gt;
        l=xoxo.fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(l,[{'good': 'buy'},['OK']])&lt;br /&gt;
&lt;br /&gt;
    def testXOXOWithSpacesAndNewlines(self):&lt;br /&gt;
        '''unmung some xoxo with spaces in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        d2={'text':'item 1',&lt;br /&gt;
            'description':&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
            'url':'http://example.com/more.xoxo',&lt;br /&gt;
            'title':'title of item 1',&lt;br /&gt;
            'type':'text/xml',&lt;br /&gt;
            'rel':'help'&lt;br /&gt;
            }&lt;br /&gt;
        xoxoAgain = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        #this needs a smarter whitespace-sensitive comparison&lt;br /&gt;
        #self.assertEqual(xoxoSample,xoxoAgain)&lt;br /&gt;
&lt;br /&gt;
    def testSpecialAttributeDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeAndDLDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in plus a &amp;lt;dl&amp;gt; in the same item and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeEncode(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        expectedHTML= '&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;' &lt;br /&gt;
        self.assertEqual(html,expectedHTML)&lt;br /&gt;
        &lt;br /&gt;
    def testSpecialAttributeRoundTripFull(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoText(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoTextOrTitle(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text or title attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testAttentionRoundTrip(self):&lt;br /&gt;
        '''check nested &amp;lt;a&amp;gt; and &amp;lt;dl&amp;gt; and &amp;lt;a&amp;gt; are preserved'''&lt;br /&gt;
        kmattn='''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;''';&lt;br /&gt;
        d = xoxo.fromXOXO(kmattn)&lt;br /&gt;
        newattn = xoxo.toXOXO(d)&lt;br /&gt;
        d2 = xoxo.fromXOXO(newattn)&lt;br /&gt;
        self.assertEqual(newattn,xoxo.toXOXO(d2))&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        self.assertEqual(kmattn,newattn)&lt;br /&gt;
        &lt;br /&gt;
    def testUnicodeRoundtrip(self):&lt;br /&gt;
        '''check unicode characters can go to xoxo and back'''&lt;br /&gt;
        src=unicode('Tantek \xc3\x87elik and a snowman \xe2\x98\x83','utf-8')&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html))&lt;br /&gt;
    def testUtf8Roundtrip(self):&lt;br /&gt;
        '''check utf8 characters can go to xoxo and back'''&lt;br /&gt;
        src='Tantek \xc3\x87elik and a snowman \xe2\x98\x83'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('utf-8'))&lt;br /&gt;
    def testWindows1252Roundtrip(self):&lt;br /&gt;
        '''check 1252 characters can go to xoxo and back'''&lt;br /&gt;
        src='This is an evil\xa0space'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('windows-1252'))&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    unittest.main()&lt;br /&gt;
else:&lt;br /&gt;
    runner = unittest.TextTestRunner()&lt;br /&gt;
    suite = unittest.makeSuite(xoxoTestCases,'test')&lt;br /&gt;
    runner.run(suite)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Java =&lt;br /&gt;
== XOXOWriter.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOWriter {&lt;br /&gt;
&lt;br /&gt;
  public String[] attrs = {&amp;quot;title&amp;quot;,&amp;quot;rel&amp;quot;,&amp;quot;type&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className){&lt;br /&gt;
    return makeXOXO(struct, className, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct, String className,&lt;br /&gt;
                         boolean doNSDeclaration){&lt;br /&gt;
    return makeXOXO(struct, className, 0, doNSDeclaration);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(List struct){&lt;br /&gt;
    return makeXOXO(struct, &amp;quot;xoxo&amp;quot;, 0, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, int depth){&lt;br /&gt;
    return makeXOXO(struct, null, 0, false);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String makeXOXO(Object struct, String className,&lt;br /&gt;
                         int depth, boolean doNSDeclaration){&lt;br /&gt;
    if(struct == null) return &amp;quot;&amp;quot;;&lt;br /&gt;
    StringBuffer sb = new StringBuffer();&lt;br /&gt;
    if(struct instanceof Object[]){&lt;br /&gt;
      struct = Arrays.asList((Object[]) struct);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof List){&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;ol&amp;quot;);&lt;br /&gt;
      if(doNSDeclaration)&lt;br /&gt;
        sb.append(&amp;quot; xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;quot;);&lt;br /&gt;
      if(className != null){&lt;br /&gt;
        sb.append(&amp;quot; class=\&amp;quot;&amp;quot;);&lt;br /&gt;
        sb.append(className);&lt;br /&gt;
        sb.append(&amp;quot;\&amp;quot;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;gt;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(struct instanceof Map){&lt;br /&gt;
      Map d = new LinkedHashMap((Map) struct);&lt;br /&gt;
      if(d.containsKey(&amp;quot;url&amp;quot;)){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;a href=\&amp;quot;&amp;quot; + d.get(&amp;quot;url&amp;quot;) + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
        Object text;&lt;br /&gt;
        if(d.containsKey(&amp;quot;text&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;text&amp;quot;);&lt;br /&gt;
        }else if(d.containsKey(&amp;quot;title&amp;quot;)){&lt;br /&gt;
          text = d.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
          text = d.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        for(int i=0; i&amp;lt;attrs.length; i++){&lt;br /&gt;
          String xVal = makeXOXO(d.get(attrs[i]),depth+1);&lt;br /&gt;
          if(xVal != null &amp;amp;&amp;amp; !xVal.equals(&amp;quot;&amp;quot;)){&lt;br /&gt;
            sb.append(attrs[i] + &amp;quot;=\&amp;quot;&amp;quot; + xVal + &amp;quot;\&amp;quot; &amp;quot;);&lt;br /&gt;
          }&lt;br /&gt;
          d.remove(attrs[i]);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;gt;&amp;quot; + makeXOXO(text, depth+1) + &amp;quot;&amp;lt;/a&amp;gt;&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;text&amp;quot;);&lt;br /&gt;
        d.remove(&amp;quot;url&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      if(d.size() &amp;gt; 0){&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;);&lt;br /&gt;
        for(Iterator i = d.keySet().iterator(); i.hasNext();){&lt;br /&gt;
          Object k = i.next();&lt;br /&gt;
          String ddVal = makeXOXO(d.get(k),depth+1);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dt&amp;gt;&amp;quot; + k + &amp;quot;&amp;lt;/dt&amp;gt;&amp;quot;);&lt;br /&gt;
          sb.append(&amp;quot;&amp;lt;dd&amp;gt;&amp;quot; + ddVal + &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
    }else if(struct instanceof List){&lt;br /&gt;
      List l = (List) struct;&lt;br /&gt;
      for(Iterator i = l.iterator(); i.hasNext();){&lt;br /&gt;
        Object item = i.next();&lt;br /&gt;
        sb.append(&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,depth+1) + &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      sb.append(&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;);&lt;br /&gt;
    }else{&lt;br /&gt;
      sb.append(struct);&lt;br /&gt;
    }&lt;br /&gt;
    return sb.toString();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct){&lt;br /&gt;
    return toXOXO(struct, false, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(Object struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    List alist = new ArrayList();&lt;br /&gt;
    alist.add(struct);&lt;br /&gt;
    return toXOXO(alist, addHTMLWrapper, cssUrl);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String toXOXO(List struct,&lt;br /&gt;
                       boolean addHTMLWrapper,&lt;br /&gt;
                       String cssUrl){&lt;br /&gt;
    String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;quot;;&lt;br /&gt;
    if(addHTMLWrapper){&lt;br /&gt;
      String s = startHTML;&lt;br /&gt;
      if(cssUrl != null){&lt;br /&gt;
        s += &amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot;&amp;gt;@import \&amp;quot;&amp;quot;&lt;br /&gt;
            + cssUrl + &amp;quot;\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      s += &amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot; + makeXOXO(struct, &amp;quot;xoxo&amp;quot;, false)&lt;br /&gt;
          + &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
      return s;&lt;br /&gt;
    }else{&lt;br /&gt;
      return makeXOXO(struct, &amp;quot;xoxo&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOParser.java ==&lt;br /&gt;
Ceci a besoin de quelques petits ajouts pour gérer les entités XHTML DTD et digits nommés.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo;&lt;br /&gt;
&lt;br /&gt;
import org.xml.sax.InputSource;&lt;br /&gt;
import org.xml.sax.SAXException;&lt;br /&gt;
import org.xml.sax.XMLReader;&lt;br /&gt;
import org.xml.sax.Attributes;&lt;br /&gt;
import org.xml.sax.helpers.XMLReaderFactory;&lt;br /&gt;
import org.xml.sax.helpers.DefaultHandler;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
import java.io.InputStream;&lt;br /&gt;
import java.io.StringReader;&lt;br /&gt;
import java.io.IOException;&lt;br /&gt;
&lt;br /&gt;
public class XOXOParser extends DefaultHandler {&lt;br /&gt;
&lt;br /&gt;
  protected String XHTML_NS = &amp;quot;http://www.w3.org/1999/xhtml&amp;quot;;&lt;br /&gt;
  protected List elStack;&lt;br /&gt;
  protected Map listEls;&lt;br /&gt;
  public List structs;&lt;br /&gt;
  public List xoStack;&lt;br /&gt;
  public List textStack;&lt;br /&gt;
&lt;br /&gt;
  public XOXOParser() {&lt;br /&gt;
    reset();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void pushStruct(Object struct){&lt;br /&gt;
    if((struct instanceof Map) &amp;amp;&amp;amp; (((Map) struct).size() &amp;gt; 0)&lt;br /&gt;
        &amp;amp;&amp;amp; (structs.get(structs.size()-1) instanceof Map)&lt;br /&gt;
        &amp;amp;&amp;amp; (((Map) struct).containsKey(&amp;quot;url&amp;quot;))){&lt;br /&gt;
      // put back the &amp;lt;a&amp;gt;-made one for extra defs&lt;br /&gt;
      xoStack.add(structs.get(structs.size()-1));&lt;br /&gt;
    }else{&lt;br /&gt;
      structs.add(struct);&lt;br /&gt;
      xoStack.add(struct);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void startElement(String nsUri, String localName,&lt;br /&gt;
                           String qName, Attributes atts){&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri.equals(XHTML_NS)){&lt;br /&gt;
      elStack.add(localName);&lt;br /&gt;
    }else{&lt;br /&gt;
      elStack.add(&amp;quot;foo&amp;quot;);&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      Map attmap = new LinkedHashMap();&lt;br /&gt;
      int len = atts.getLength();&lt;br /&gt;
      for(int i=0; i&amp;lt;len; i++){&lt;br /&gt;
        attmap.put(atts.getQName(i),atts.getValue(i));&lt;br /&gt;
      }&lt;br /&gt;
      if(attmap.containsKey(&amp;quot;href&amp;quot;)){&lt;br /&gt;
        attmap.put(&amp;quot;url&amp;quot;,attmap.get(&amp;quot;href&amp;quot;));&lt;br /&gt;
        attmap.remove(&amp;quot;href&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
      pushStruct(attmap);&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      pushStruct(new LinkedHashMap());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      pushStruct(new ArrayList());&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dt&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      textStack.add(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void endElement(String nsUri, String localName,&lt;br /&gt;
                         String qName){&lt;br /&gt;
    elStack.remove(elStack.size()-1);&lt;br /&gt;
    // bounce non-XHTML elements&lt;br /&gt;
    if(nsUri != XHTML_NS){&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(localName.equals(&amp;quot;a&amp;quot;)){&lt;br /&gt;
      String val = (String) textStack.remove(textStack.size()-1);&lt;br /&gt;
      if (val.length() &amp;gt; 0){&lt;br /&gt;
        Map defs = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
        String defVal = (String) defs.get(&amp;quot;title&amp;quot;);&lt;br /&gt;
        if((defVal != null) &amp;amp;&amp;amp; (val.equals(defVal))){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        defVal = (String) defs.get(&amp;quot;url&amp;quot;);&lt;br /&gt;
        if((defVal != null) &amp;amp;&amp;amp; (val.equals(defVal))){&lt;br /&gt;
          val = &amp;quot;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        if(val.length() &amp;gt; 0){&lt;br /&gt;
          defs.put(&amp;quot;text&amp;quot;,val);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dl&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ol&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;ul&amp;quot;)){&lt;br /&gt;
      xoStack.remove(xoStack.size()-1);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;li&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      List last = (List) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.add(val);&lt;br /&gt;
    }else if(localName.equals(&amp;quot;dd&amp;quot;)){&lt;br /&gt;
      Object val = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Object key = textStack.remove(textStack.size()-1);&lt;br /&gt;
      Map last = (Map) xoStack.get(xoStack.size()-1);&lt;br /&gt;
      if(structs.get(structs.size()-1) != last){&lt;br /&gt;
        val = structs.remove(structs.size()-1);&lt;br /&gt;
      }&lt;br /&gt;
      last.put(key,val);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void characters(char[] ch, int start, int length){&lt;br /&gt;
    if((xoStack.size() &amp;gt; 0)&lt;br /&gt;
        &amp;amp;&amp;amp; (!listEls.containsKey(elStack.get(elStack.size()-1)))){&lt;br /&gt;
      String text = (String) textStack.get(textStack.size()-1);&lt;br /&gt;
      String test = new String(ch,start,length);&lt;br /&gt;
      textStack.set(textStack.size()-1,text+test);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(String s) throws SAXException, IOException{&lt;br /&gt;
    return parse(new InputSource(new StringReader(s)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputStream is) throws SAXException, IOException {&lt;br /&gt;
    return parse(new InputSource(is));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public Object parse(InputSource in) throws SAXException, IOException {&lt;br /&gt;
    XMLReader parser = XMLReaderFactory.createXMLReader();&lt;br /&gt;
    parser.setContentHandler(this);&lt;br /&gt;
    parser.parse(in);&lt;br /&gt;
    List returnList = new ArrayList();&lt;br /&gt;
    for(Iterator i = this.structs.iterator(); i.hasNext();){&lt;br /&gt;
      Object thing = i.next();&lt;br /&gt;
      if(thing != null){&lt;br /&gt;
        returnList.add(thing);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    while((returnList.size()==1)){&lt;br /&gt;
      if(returnList.get(0) instanceof List){&lt;br /&gt;
        returnList = (List) returnList.get(0);&lt;br /&gt;
      }else{&lt;br /&gt;
        reset();&lt;br /&gt;
        return returnList.get(0);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    reset();&lt;br /&gt;
    return returnList;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  protected void reset(){&lt;br /&gt;
    elStack = new ArrayList();&lt;br /&gt;
    listEls = new HashMap();&lt;br /&gt;
    structs = new ArrayList();&lt;br /&gt;
    xoStack = new ArrayList();&lt;br /&gt;
    textStack = new ArrayList();&lt;br /&gt;
    listEls.put(&amp;quot;ol&amp;quot;,&amp;quot;ol&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;ul&amp;quot;,&amp;quot;ul&amp;quot;);&lt;br /&gt;
    listEls.put(&amp;quot;dl&amp;quot;,&amp;quot;dl&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== XOXOTest.java ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright 2005 Robert Sayre&lt;br /&gt;
 *&lt;br /&gt;
 * Licensed under the Apache License, Version 2.0 (the &amp;quot;License&amp;quot;);&lt;br /&gt;
 * you may not use this file except in compliance with the License.&lt;br /&gt;
 * You may obtain a copy of the License at&lt;br /&gt;
 * &lt;br /&gt;
 *      http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt;
 * &lt;br /&gt;
 * Unless required by applicable law or agreed to in writing, software&lt;br /&gt;
 * distributed under the License is distributed on an &amp;quot;AS IS&amp;quot; BASIS,&lt;br /&gt;
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt;
 * See the License for the specific language governing permissions and&lt;br /&gt;
 * limitations under the License.&lt;br /&gt;
 *&lt;br /&gt;
 * Portions of this code are derived from the Apache-licensed Python XOXO&lt;br /&gt;
 * module by Kevin Marks. &amp;lt;http://microformats.org/wiki/xoxo-sample-code&amp;gt;&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
package org.atompub.draft.xoxo.tests;&lt;br /&gt;
&lt;br /&gt;
import junit.framework.TestSuite;&lt;br /&gt;
import junit.framework.TestCase;&lt;br /&gt;
import junit.textui.TestRunner;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOWriter;&lt;br /&gt;
import org.atompub.draft.xoxo.XOXOParser;&lt;br /&gt;
&lt;br /&gt;
import java.util.*;&lt;br /&gt;
&lt;br /&gt;
public class XOXOTest extends TestCase {&lt;br /&gt;
&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    new TestRunner().doRun(new TestSuite(XOXOTest.class));&lt;br /&gt;
  }&lt;br /&gt;
  String XHTML_DEC = &amp;quot;xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot; &amp;quot;;&lt;br /&gt;
  public String simpleListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSimpleList(){&lt;br /&gt;
    String [] numbers = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testStringIntegerList(){&lt;br /&gt;
    Object[] numbers = {new Integer(1),&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(simpleListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(numbers)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String nestedListHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testNestedList(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,Arrays.asList(arr)};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testNestedArray(){&lt;br /&gt;
    Object[] arr = {&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] nested = {&amp;quot;1&amp;quot;,arr};&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(nestedListHTML,&lt;br /&gt;
                 xoxo.toXOXO(Arrays.asList(nested)));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String dictHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testDictionary(){&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, new Integer(1));&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(dictHTML,&lt;br /&gt;
                 xoxo.toXOXO(dict));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String singleHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(singleHTML,&lt;br /&gt;
                 xoxo.toXOXO(item));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testWrapDiffers(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String nowrap = xoxo.toXOXO(item);&lt;br /&gt;
    Object[] itemArr = {item};&lt;br /&gt;
    String wrap = xoxo.toXOXO(Arrays.asList(itemArr),true,null);&lt;br /&gt;
    assertFalse(wrap.equals(nowrap));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  String startHTML = &amp;quot;&amp;lt;!DOCTYPE html PUBLIC \&amp;quot;-//W3C//DTD&amp;quot;&lt;br /&gt;
        + &amp;quot;XHTML 1.0 Transitional//EN\n&amp;quot;&lt;br /&gt;
        + &amp;quot;http://www.w3.org/TR/xhtml1/DTD/&amp;quot;&lt;br /&gt;
        + &amp;quot;xhtml1-transitional.dtd\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;html xmlns=\&amp;quot;http://www.w3.org/1999/xhtml\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
        + &amp;quot;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;;&lt;br /&gt;
  public String singleWrapHTML = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
  public String endHTML = &amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testWrapSingleItem(){&lt;br /&gt;
    String item = &amp;quot;test&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    assertEquals(startHTML + singleWrapHTML + endHTML,&lt;br /&gt;
                 xoxo.toXOXO(item,true,null));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOParser(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      parser.parse(dictHTML);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
     try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListRoundTrip(){&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfDictsRoundTrip(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;test&amp;quot;, &amp;quot;1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;name&amp;quot;, &amp;quot;Kevin&amp;quot;);&lt;br /&gt;
    Map dict2 = new LinkedHashMap();&lt;br /&gt;
    dict2.put(&amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;three&amp;quot;, &amp;quot;four&amp;quot;);&lt;br /&gt;
    dict2.put(&amp;quot;five&amp;quot;, &amp;quot;six&amp;quot;);&lt;br /&gt;
    Object[] obj = {&amp;quot;1&amp;quot;,dict,dict2};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testListOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;, Arrays.asList(list1)};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;, Arrays.asList(list2)};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, Arrays.asList(list3)};&lt;br /&gt;
    List testList = Arrays.asList(list4);&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(testList);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(html);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testDictOfListsRoundTrip(){&lt;br /&gt;
    Object[] list1 = {&amp;quot;1&amp;quot;,&amp;quot;2&amp;quot;,&amp;quot;3&amp;quot;};&lt;br /&gt;
    Object[] list2 = {&amp;quot;4&amp;quot;,&amp;quot;5&amp;quot;,&amp;quot;6&amp;quot;};&lt;br /&gt;
    Object[] list3 = {&amp;quot;7&amp;quot;};&lt;br /&gt;
    Object[] list4 = {&amp;quot;8&amp;quot;, &amp;quot;9&amp;quot;};&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;foo&amp;quot;, Arrays.asList(list1));&lt;br /&gt;
    dict.put(&amp;quot;bar&amp;quot;, Arrays.asList(list2));&lt;br /&gt;
    dict.put(&amp;quot;baz&amp;quot;, Arrays.asList(list3));&lt;br /&gt;
    dict.put(&amp;quot;qux&amp;quot;, Arrays.asList(list4));&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOJunkInContainers(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(junkXOXO);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String junkElementXOXO = &amp;quot;&amp;lt;ol &amp;quot;&lt;br /&gt;
  + XHTML_DEC&lt;br /&gt;
  + &amp;quot;&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
  + &amp;quot;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOjunkInElements(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;good&amp;quot;,&amp;quot;buy&amp;quot;);&lt;br /&gt;
    Object[] ok = {&amp;quot;OK&amp;quot;};&lt;br /&gt;
    Object[] obj ={dict, Arrays.asList(ok)};&lt;br /&gt;
    List testList = Arrays.asList(obj);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newList = parser.parse(junkElementXOXO);&lt;br /&gt;
      assertEquals(testList,newList);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSpacesNewlines = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt; This item represents the main&amp;quot; +&lt;br /&gt;
      &amp;quot; point we're trying to make.&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testXOXOWithSpacesAndNewlines(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;description&amp;quot;,&amp;quot; This item represents the main&amp;quot; +&lt;br /&gt;
        &amp;quot; point we're trying to make.&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;title of item 1&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(xoxoSpacesNewlines);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String xoxoSample = &amp;quot;&amp;lt;ol &amp;quot; +  XHTML_DEC +&lt;br /&gt;
      &amp;quot; class='xoxo'&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;    &amp;lt;/dl&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public String smartXOXOSample = &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         title=\&amp;quot;title of item 1\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         type=\&amp;quot;text/xml\&amp;quot;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; \n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply&amp;quot; +&lt;br /&gt;
      &amp;quot; the contents of the &amp;lt;a&amp;gt; element --&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;  &amp;lt;/li&amp;gt;\n&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeDecoding(){&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    try{&lt;br /&gt;
      Object xoxoDict = parser.parse(xoxoSample);&lt;br /&gt;
      Object xoxoDict2 = parser.parse(smartXOXOSample);&lt;br /&gt;
      assertEquals(xoxoDict,xoxoDict2);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String specialAttrHTML =  &amp;quot;&amp;lt;ol &amp;quot; + XHTML_DEC +&lt;br /&gt;
      &amp;quot;class=\&amp;quot;xoxo\&amp;quot;&amp;gt;&amp;quot; +&lt;br /&gt;
      &amp;quot;&amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot; title=\&amp;quot;sample url\&amp;quot; &amp;quot; +&lt;br /&gt;
      &amp;quot;rel=\&amp;quot;help\&amp;quot; type=\&amp;quot;text/xml\&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeEncode(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    assertEquals(specialAttrHTML,html);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripFull(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;text&amp;quot;,&amp;quot;an example&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoText(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;title&amp;quot;,&amp;quot;sample url&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testSpecialAttributeRoundTripNoTextOrTitle(){&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    Map dict = new LinkedHashMap();&lt;br /&gt;
    dict.put(&amp;quot;url&amp;quot;,&amp;quot;http://example.com/more.xoxo&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;type&amp;quot;,&amp;quot;text/xml&amp;quot;);&lt;br /&gt;
    dict.put(&amp;quot;rel&amp;quot;,&amp;quot;help&amp;quot;);&lt;br /&gt;
    String html = xoxo.toXOXO(dict);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newDict = parser.parse(html);&lt;br /&gt;
      assertEquals(dict,newDict);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void testUnicodeRoundTrip(){&lt;br /&gt;
    String s = &amp;quot;Tantek Çelik and a snowman ?&amp;quot;;&lt;br /&gt;
    XOXOWriter xoxo = new XOXOWriter();&lt;br /&gt;
    XOXOParser parser = new XOXOParser();&lt;br /&gt;
    String html = xoxo.toXOXO(s);&lt;br /&gt;
    try{&lt;br /&gt;
      Object newString = parser.parse(html);&lt;br /&gt;
      assertEquals(s,newString);&lt;br /&gt;
    }catch (Exception e){&lt;br /&gt;
      fail(e.getMessage());&lt;br /&gt;
      e.printStackTrace();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= PHP =&lt;br /&gt;
== xoxolib.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
function getKind($struct)&lt;br /&gt;
{&lt;br /&gt;
    if (!is_array($struct)) return 'string';&lt;br /&gt;
    if (!isset($struct[0]))&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    else if (array_keys($struct)==range(0,count($struct)-1))&lt;br /&gt;
        $result = 'list';&lt;br /&gt;
    else&lt;br /&gt;
        $result = 'dictionary';&lt;br /&gt;
    return $result;&lt;br /&gt;
}&lt;br /&gt;
function makeXOXO($struct,$className='')&lt;br /&gt;
{&lt;br /&gt;
    $s='';&lt;br /&gt;
    $kind = getKind($struct);&lt;br /&gt;
    #echo &amp;quot;$kind:\n&amp;quot;;&lt;br /&gt;
    #var_dump($struct);&lt;br /&gt;
    if ($kind=='list')&lt;br /&gt;
        {&lt;br /&gt;
        if ($className)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol class=\&amp;quot;$className\&amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
        else &lt;br /&gt;
            $s .= &amp;quot;&amp;lt;ol&amp;gt;&amp;quot;;&lt;br /&gt;
        foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;li&amp;gt;&amp;quot; . makeXOXO($value) .&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
    else if ($kind=='dictionary')&lt;br /&gt;
        {&lt;br /&gt;
        if (isset($struct['url']))&lt;br /&gt;
            {&lt;br /&gt;
            $s .='&amp;lt;a href=&amp;quot;' .$struct['url']. '&amp;quot; ';&lt;br /&gt;
            if (isset($struct['text']))&lt;br /&gt;
                $text= $struct['text'];&lt;br /&gt;
            else if (isset($struct['title']))&lt;br /&gt;
                $text= $struct['title'];&lt;br /&gt;
            else&lt;br /&gt;
                $text= $struct['url'];&lt;br /&gt;
            foreach (array('title','rel','type') as $attr)&lt;br /&gt;
                if (isset($struct[$attr]))&lt;br /&gt;
                    {&lt;br /&gt;
                    $s .= &amp;quot;$attr=\&amp;quot;&amp;quot; . $struct[$attr] .'&amp;quot; ';&lt;br /&gt;
                    unset($struct[$attr]);&lt;br /&gt;
                    }&lt;br /&gt;
            $s .= &amp;quot;&amp;gt;&amp;quot; . makeXOXO($text) .&amp;quot;&amp;lt;/a&amp;gt;&amp;quot;;&lt;br /&gt;
            unset($struct['url'],$struct['text']);&lt;br /&gt;
            }&lt;br /&gt;
        if (count($struct))&lt;br /&gt;
            {&lt;br /&gt;
            $s .=&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
            foreach ($struct as $key =&amp;gt; $value)&lt;br /&gt;
                $s .= &amp;quot;&amp;lt;dt&amp;gt;$key&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;quot;. makeXOXO($value) . &amp;quot;&amp;lt;/dd&amp;gt;&amp;quot;;&lt;br /&gt;
            $s .= &amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    else&lt;br /&gt;
        $s .= &amp;quot;$struct&amp;quot;;&lt;br /&gt;
    #echo &amp;quot;returned $s\n&amp;quot;;&lt;br /&gt;
    return $s;&lt;br /&gt;
}&lt;br /&gt;
function toXOXO($struct,$addHTMLWrapper=FALSE,$cssUrl='')&lt;br /&gt;
{&lt;br /&gt;
    if (getKind($struct) != 'list')&lt;br /&gt;
        $struct = array($struct);&lt;br /&gt;
    $xoxo = makeXOXO($struct,'xoxo');&lt;br /&gt;
    if ($addHTMLWrapper)&lt;br /&gt;
        {&lt;br /&gt;
        $s= '&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;';&lt;br /&gt;
        if ($cssUrl) $s .=&amp;quot;&amp;lt;style type=\&amp;quot;text/css\&amp;quot; &amp;gt;@import \&amp;quot;$cssUrl\&amp;quot;;&amp;lt;/style&amp;gt;&amp;quot;;&lt;br /&gt;
        $s .=&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;$xoxo&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;;&lt;br /&gt;
        return $s;&lt;br /&gt;
        }&lt;br /&gt;
    return $xoxo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function pushStruct($struct,&amp;amp;$structstack,&amp;amp;$xostack,$structType)&lt;br /&gt;
{&lt;br /&gt;
    if (is_array($struct) &amp;amp;&amp;amp; $structType=='dict' &amp;amp;&amp;amp; count($structstack) &amp;amp;&amp;amp; is_array(end($structstack)) &amp;amp;&amp;amp; isset($structstack[count($structstack)-1]['url']) &amp;amp;&amp;amp; end($structstack) != end($xostack))&lt;br /&gt;
        $xostack[] = &amp;amp;$structstack[count($structstack)-1]; # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
    else&lt;br /&gt;
        {&lt;br /&gt;
        $structstack[]=$struct;&lt;br /&gt;
        $xostack[]=&amp;amp;$structstack[count($structstack)-1];&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fromXOXO($html)&lt;br /&gt;
{&lt;br /&gt;
    $structs=array();&lt;br /&gt;
    $xostack=array();&lt;br /&gt;
    $textstack=array('');&lt;br /&gt;
    $dumpStacks=0;&lt;br /&gt;
    $p = xml_parser_create();&lt;br /&gt;
    xml_parse_into_struct($p, $html, $xoxoVals, $xoxoIndex);&lt;br /&gt;
    xml_parser_free($p);&lt;br /&gt;
&lt;br /&gt;
  if($dumpStacks)&lt;br /&gt;
        {&lt;br /&gt;
        echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
        var_dump($xoxoVals);&lt;br /&gt;
        var_dump($xoxoIndex);&lt;br /&gt;
        echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;; &lt;br /&gt;
        }&lt;br /&gt;
    $howmany = sizeof($xoxoVals);&lt;br /&gt;
    &lt;br /&gt;
    #echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    $x = $xoxoIndex['OL'];&lt;br /&gt;
    for ($x=0;$x&amp;lt;$howmany;++$x)&lt;br /&gt;
        {&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'OL' || $xoxoVals[$x]['tag'] == 'DL'|| $xoxoVals[$x]['tag'] == 'UL')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['tag'] == 'DL')&lt;br /&gt;
                $structType = 'dict';&lt;br /&gt;
            else &lt;br /&gt;
                $structType = 'list';&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'open')&lt;br /&gt;
                pushStruct(array(),$structs,$xostack,$structType);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'LI')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
               array_push($xostack[count($xostack)-1],$xoxoVals[$x]['value']);&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                array_push($xostack[count($xostack)-1],array_pop($structs));&lt;br /&gt;
                }&lt;br /&gt;
            if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DT')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                array_push($textstack,$xoxoVals[$x]['value']);&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'DD')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] = $xoxoVals[$x]['value'];&lt;br /&gt;
                }&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'close')&lt;br /&gt;
                {&lt;br /&gt;
                $key = array_pop($textstack);&lt;br /&gt;
                $xostack[count($xostack)-1][$key] =array_pop($structs);&lt;br /&gt;
                }&lt;br /&gt;
          if($dumpStacks)&lt;br /&gt;
                {&lt;br /&gt;
                echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                var_dump($structs);&lt;br /&gt;
                var_dump($xostack);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        if ($xoxoVals[$x]['tag'] == 'A')&lt;br /&gt;
            {&lt;br /&gt;
            if ($xoxoVals[$x]['type'] == 'complete')&lt;br /&gt;
                {&lt;br /&gt;
                $attrs = $xoxoVals[$x]['attributes'];&lt;br /&gt;
                $dict=array();&lt;br /&gt;
                foreach ($attrs as $key=&amp;gt; $value)&lt;br /&gt;
                    {&lt;br /&gt;
                    if ($key=='HREF')&lt;br /&gt;
                        $dict['url'] = $value;&lt;br /&gt;
                    else&lt;br /&gt;
                        $dict[strtolower($key)] = $value;&lt;br /&gt;
                    }&lt;br /&gt;
                $val = $xoxoVals[$x]['value'];&lt;br /&gt;
                if (isset($val) &amp;amp;&amp;amp; ($val != $dict['title']) &amp;amp;&amp;amp; ($val != $dict['url']))&lt;br /&gt;
                    $dict['text'] = $val;&lt;br /&gt;
                pushStruct($dict,$structs,$xostack,'dict');&lt;br /&gt;
                array_pop($xostack);&lt;br /&gt;
 &lt;br /&gt;
                if($dumpStacks)&lt;br /&gt;
                    {&lt;br /&gt;
                    echo $xoxoVals[$x]['type'] .' ' . $xoxoVals[$x]['tag'] .&amp;quot;:\n&amp;quot;;&lt;br /&gt;
                    var_dump($structs);&lt;br /&gt;
                    var_dump($xostack);&lt;br /&gt;
                    }&lt;br /&gt;
               }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
     #echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;quot;;&lt;br /&gt;
   while (count($structs) == 1 &amp;amp;&amp;amp; getKind($structs) == 'list')&lt;br /&gt;
        $structs = $structs[0];&lt;br /&gt;
    return $structs;&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== xoxotest.php ==&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?&lt;br /&gt;
include(&amp;quot;xoxolib.php&amp;quot;);&lt;br /&gt;
function assertEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 == $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;$str2&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function assertArrayEqual($testname,$expected,$returned)&lt;br /&gt;
{&lt;br /&gt;
if ($expected == $returned)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname &amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;expected&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($expected);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dt&amp;gt;returned&amp;lt;/dt&amp;gt;\n&amp;lt;dd&amp;gt;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
    var_dump($returned);&lt;br /&gt;
    echo &amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/dd&amp;gt;\n&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function failIfEqual($testname,$str1,$str2)&lt;br /&gt;
{&lt;br /&gt;
if ($str1 != $str2)&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;amp;#x221a; $testname&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
else &lt;br /&gt;
    {&lt;br /&gt;
    echo &amp;quot;&amp;lt;h3&amp;gt;&amp;lt;big&amp;gt;&amp;amp;#x2639;&amp;lt;/big&amp;gt; $testname failed&amp;lt;/h3&amp;gt;&amp;quot;;&lt;br /&gt;
    echo &amp;quot;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;both were&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;$str1&amp;lt;/dd&amp;gt;&amp;lt;dl&amp;gt;&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$l = array('1','2','3');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$s = 'test';&lt;br /&gt;
$html = toXOXO($s);&lt;br /&gt;
assertEqual(&amp;quot;make xoxo from a string&amp;quot;,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$htmlwrap = toXOXO($s,TRUE);&lt;br /&gt;
failIfEqual(&amp;quot;make sure wrapped and unwrapped differ&amp;quot;,html,htmlwrap);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$htmlwrap);&lt;br /&gt;
$csswrap = toXOXO($s,TRUE,&amp;quot;reaptest.css&amp;quot;);&lt;br /&gt;
assertEqual(&amp;quot;make wrapped xoxo with css link from a string&amp;quot;,'&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;',$csswrap);&lt;br /&gt;
$l2 = array('1',array('2','3'));&lt;br /&gt;
$html = toXOXO($l2);&lt;br /&gt;
assertEqual('make xoxo from nested list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from 1-element dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','thing'=&amp;gt;'and another thing...');&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and thing','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;thing&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;and another thing...&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$d = array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example','list'=&amp;gt;array('and', 'another','thing...'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
assertEqual('make xoxo from dictionary with url and list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;list&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;and&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;another&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;thing...&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
assertEqual('make xoxo from dict in list','&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;a&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;2&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;',$html);&lt;br /&gt;
&lt;br /&gt;
$l = array('3','2','1');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list to xoxo and back',$l,$newdl);&lt;br /&gt;
$l = array('1',array('a','b'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
&lt;br /&gt;
$l= array('3',array('a','2'),array('b',array('1',array('c','4'))));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of list of lists to xoxo and back',$l,$newdl);&lt;br /&gt;
$d = array(test=&amp;gt;'1',name=&amp;gt;Kevin);&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$l = array('3',array('a'=&amp;gt;'2'),array('b'=&amp;gt;'1','c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('list of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('list of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'two'=&amp;gt;array('c'=&amp;gt;'4'));&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$l = array('one'=&amp;gt;array('a'=&amp;gt;'2','b'=&amp;gt;'3'),'url'=&amp;gt;'http://example.com');&lt;br /&gt;
$html = toXOXO($l);&lt;br /&gt;
$newdl= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dict of dicts with url to xoxo and back',$l,$newdl);&lt;br /&gt;
assertEqual('dict of dicts with url to xoxo and back',$html,toXOXO($newdl));&lt;br /&gt;
$d = array('test'=&amp;gt; array('1','2'),&lt;br /&gt;
'name'=&amp;gt; 'Kevin','nestlist'=&amp;gt; array('a',array('b','c')),&lt;br /&gt;
'nestdict'=&amp;gt;array('e'=&amp;gt;'6','f'=&amp;gt;'7'));&lt;br /&gt;
$html = toXOXO($d);&lt;br /&gt;
$newd= fromXOXO($html);&lt;br /&gt;
assertArrayEqual('dictionary of lists  to xoxo and back',$d,$newd);&lt;br /&gt;
&lt;br /&gt;
$d=fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text outside &amp;amp;lt;li&amp;amp;gt; etc is ignored',array(good=&amp;gt;buy),$d);&lt;br /&gt;
&lt;br /&gt;
$l=fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;');&lt;br /&gt;
assertArrayEqual('make sure text within &amp;amp;lt;li&amp;amp;gt; but outside a subcontainer is ignored',array(array(good=&amp;gt;buy),array('OK')),$l);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$d2=array('text'=&amp;gt;'item 1',&lt;br /&gt;
    'description'=&amp;gt;&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
    'url'=&amp;gt;'http://example.com/more.xoxo',&lt;br /&gt;
    'title'=&amp;gt;'title of item 1',&lt;br /&gt;
    'type'=&amp;gt;'text/xml',&lt;br /&gt;
    'rel'=&amp;gt;'help');&lt;br /&gt;
assertArrayEqual('unmung some xoxo with spaces in and check result is right',$d2,$d);&lt;br /&gt;
&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
$xoxoSample= &amp;quot;&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d = fromXOXO($xoxoSample);&lt;br /&gt;
$smartxoxoSample= &amp;quot;&amp;lt;ol class=\&amp;quot;xoxo\&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=\&amp;quot;http://example.com/more.xoxo\&amp;quot;&lt;br /&gt;
         title=\&amp;quot;title of item 1\&amp;quot;&lt;br /&gt;
         type=\&amp;quot;text/xml\&amp;quot;&lt;br /&gt;
         rel=\&amp;quot;help\&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the \&amp;quot;text\&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&amp;quot;;&lt;br /&gt;
$d2 = fromXOXO($smartxoxoSample);&lt;br /&gt;
assertArrayEqual('unmung some xoxo with &amp;amp;lt;a href= rel= etc in and check result is right',$d,$d2);&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help','text'=&amp;gt;'an example');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo','title'=&amp;gt;'sample url','type'=&amp;gt;&amp;quot;text/xml&amp;quot;,'rel'=&amp;gt;'help');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (no text)',$d,fromXOXO($html));&lt;br /&gt;
&lt;br /&gt;
$d=array('url'=&amp;gt;'http://example.com/more.xoxo');&lt;br /&gt;
$html=toXOXO($d);&lt;br /&gt;
assertArrayEqual('round trip url to href to url (just url)',$d,fromXOXO($html));&lt;br /&gt;
$kmattn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
$d=fromXOXO($kmattn);&lt;br /&gt;
$newattn = toXOXO($d);&lt;br /&gt;
$d2=fromXOXO($newattn);&lt;br /&gt;
assertArrayEqual('attention double round-trip',$d,$d2);&lt;br /&gt;
assertEqual('attention triple round-trip',$newattn,toXOXO($d2));&lt;br /&gt;
assertEqual('attention one round-trip',$kmattn,$newattn);&lt;br /&gt;
$d=array(array(url=&amp;gt;&amp;quot;http://www.boingboing.net/&amp;quot;,title=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://boingboing.net/rss.xml&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Boing Boing Blog&amp;quot;),array(url=&amp;gt;&amp;quot;http://www.financialcryptography.com/&amp;quot;,title=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;,&amp;quot;alturls&amp;quot;=&amp;gt;array(array(&amp;quot;url&amp;quot;=&amp;gt;&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot;,&amp;quot;text&amp;quot;=&amp;gt;&lt;br /&gt;
&amp;quot;xmlurl&amp;quot;)),&amp;quot;description&amp;quot;=&amp;gt;&amp;quot;Financial Cryptography&amp;quot;));&lt;br /&gt;
$attn=&amp;lt;&amp;lt;&amp;lt;ENDATTN&lt;br /&gt;
&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
ENDATTN;&lt;br /&gt;
assertEqual('attention encode',$attn,toXOXO($d));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
== autres implémentations ==&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/xoxo2array.php.txt xoxo2array.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/array2xoxo.php.txt array2xoxo.php]&lt;br /&gt;
* [http://boxtheweb.mihopa.net/code/apis/#outlineclasses Outline Classes]&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
	<entry>
		<id>https://microformats.org/wiki/index.php?title=xoxo-sample-code-python&amp;diff=41463</id>
		<title>xoxo-sample-code-python</title>
		<link rel="alternate" type="text/html" href="https://microformats.org/wiki/index.php?title=xoxo-sample-code-python&amp;diff=41463"/>
		<updated>2009-11-29T05:09:43Z</updated>

		<summary type="html">&lt;p&gt;Newacct: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= XOXO Sample Code - Python=&lt;br /&gt;
:'''this is  sub-page of [[xoxo-sample-code]]'''&lt;br /&gt;
&lt;br /&gt;
== xoxo.py ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;xoxo.py - a utility module for transforming to and from the XHTMLOutlines format XOXO http://microformats.org/wiki/xoxo&lt;br /&gt;
toXOXO takes a Python datastructure (tuples, lists or dictionaries, arbitrarily nested) and returns a XOXO representation of it.&lt;br /&gt;
fromXOXO parses an XHTML file for a xoxo list and returns the structure&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__version__ = &amp;quot;0.9&amp;quot;&lt;br /&gt;
__date__ = &amp;quot;2005-11-02&amp;quot;&lt;br /&gt;
__author__ = &amp;quot;Kevin Marks &amp;lt;kmarks@technorati.com&amp;gt;&amp;quot;&lt;br /&gt;
__copyright__ = &amp;quot;Copyright 2004-2006, Kevin Marks &amp;amp; Technorati&amp;quot;&lt;br /&gt;
__license__ = &amp;quot;http://creativecommons.org/licenses/by/2.0/ CC-by-2.0], [http://www.apache.org/licenses/LICENSE-2.0 Apache 2.0&amp;quot;&lt;br /&gt;
__credits__ = &amp;quot;&amp;quot;&amp;quot;Tantek Çelik and Mark Pilgrim for data structure&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
__history__ = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
TODO: add &amp;lt;title&amp;gt; tag&lt;br /&gt;
TODO: add a proper profile link&lt;br /&gt;
0.9 smarter parsing for encoding and partial markup; fix dangling dictionary case&lt;br /&gt;
0.8 work in unicode then render to utf-8&lt;br /&gt;
0.7 initial encoding support - just utf-8 for now&lt;br /&gt;
0.6 support the special behavior for url properties  to/from &amp;lt;a&amp;gt;&lt;br /&gt;
0.5 fix some awkward side effects of whitespace and text outside our expected tags; simplify writing code&lt;br /&gt;
0.4 add correct XHTML headers so it validates&lt;br /&gt;
0.3 read/write version; fixed invalid nested list generation;&lt;br /&gt;
0.1 first write-only version&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    True, False&lt;br /&gt;
except NameError:&lt;br /&gt;
    True, False = not not 1, not 1&lt;br /&gt;
containerTags={'ol':False,'ul':False,'dl':False}&lt;br /&gt;
import sgmllib, urllib, urlparse, re,codecs&lt;br /&gt;
&lt;br /&gt;
def toUnicode(key):&lt;br /&gt;
    if type(key) == type(u'unicode'):&lt;br /&gt;
        uKey= key&lt;br /&gt;
    else:&lt;br /&gt;
        try: &lt;br /&gt;
            uKey=unicode(key,'utf-8')&lt;br /&gt;
        except:&lt;br /&gt;
            uKey=unicode(key,'windows_1252')&lt;br /&gt;
    return uKey&lt;br /&gt;
&lt;br /&gt;
def makeXOXO(struct,className=None):&lt;br /&gt;
    s=u''&lt;br /&gt;
    if isinstance(struct,list) or isinstance(struct,tuple):&lt;br /&gt;
        if className:&lt;br /&gt;
            s += u'&amp;lt;ol class=&amp;quot;%s&amp;quot;&amp;gt;' % className&lt;br /&gt;
        else:&lt;br /&gt;
            s+= u&amp;quot;&amp;lt;ol&amp;gt;&amp;quot;&lt;br /&gt;
        for item in struct:&lt;br /&gt;
            s+=u&amp;quot;&amp;lt;li&amp;gt;&amp;quot; + makeXOXO(item,None)+&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
        s +=u&amp;quot;&amp;lt;/ol&amp;gt;&amp;quot;&lt;br /&gt;
    elif isinstance(struct,dict):&lt;br /&gt;
        d=struct.copy()&lt;br /&gt;
        if 'url' in d:&lt;br /&gt;
            uURL=toUnicode(d['url'])&lt;br /&gt;
            s+=u'&amp;lt;a href=&amp;quot;%s&amp;quot; ' % uURL&lt;br /&gt;
            text =  d.get('text',d.get('title',uURL))&lt;br /&gt;
            for attr in ('title','rel','type'):&lt;br /&gt;
                if attr in d:&lt;br /&gt;
                    xVal = makeXOXO(d[attr],None)&lt;br /&gt;
                    s +=u'%s=&amp;quot;%s&amp;quot; ' % (attr,xVal)&lt;br /&gt;
                    del d[attr]&lt;br /&gt;
            s +=u'&amp;gt;%s&amp;lt;/a&amp;gt;' % makeXOXO(text,None)&lt;br /&gt;
            if 'text' in d:&lt;br /&gt;
                del d['text']&lt;br /&gt;
            del d['url']&lt;br /&gt;
        if len(d):&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;dl&amp;gt;&amp;quot;&lt;br /&gt;
            for key,value in d.items():&lt;br /&gt;
                xVal = makeXOXO(value,None)&lt;br /&gt;
                uKey=toUnicode(key)&lt;br /&gt;
                s+= u'&amp;lt;dt&amp;gt;%s&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;%s&amp;lt;/dd&amp;gt;' % (uKey, xVal)&lt;br /&gt;
            s +=u&amp;quot;&amp;lt;/dl&amp;gt;&amp;quot;&lt;br /&gt;
    elif type(struct) == type(u'unicode'):&lt;br /&gt;
        s+=struct&lt;br /&gt;
    else:&lt;br /&gt;
        if type(struct)!=type(' '):&lt;br /&gt;
            struct=str(struct)&lt;br /&gt;
        s += toUnicode(struct)&lt;br /&gt;
    return s&lt;br /&gt;
class AttrParser(sgmllib.SGMLParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        sgmllib.SGMLParser.__init__(self)&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.encoding='utf-8'&lt;br /&gt;
    def cleanText(self,inText):&lt;br /&gt;
        if type(inText) == type(u'unicode'):&lt;br /&gt;
            inText = inText.encode(self.encoding,'replace')&lt;br /&gt;
        self.text=[]&lt;br /&gt;
        self.reset()&lt;br /&gt;
        self.feed(inText)&lt;br /&gt;
        return ''.join(self.text)&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        if 'ascii' in encoding:&lt;br /&gt;
            encoding='windows_1252' # so we don't throw an exception on high-bit set chars in there by mistake&lt;br /&gt;
        if encoding and encoding !='text/html':&lt;br /&gt;
            try:&lt;br /&gt;
                canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                self.encoding = encoding&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    encoding='japanese.' +encoding&lt;br /&gt;
                    canDecode = codecs.getdecoder(encoding)&lt;br /&gt;
                    self.encoding = encoding&lt;br /&gt;
                except:&lt;br /&gt;
                    print &amp;quot;can't deal with encoding %s&amp;quot; % encoding&lt;br /&gt;
                    &lt;br /&gt;
    def handle_entityref(self, ref):&lt;br /&gt;
        # called for each entity reference, e.g. for &amp;quot;&amp;amp;copy;&amp;quot;, ref will be &amp;quot;copy&amp;quot;&lt;br /&gt;
        # map through to unicode where we can&lt;br /&gt;
        try:&lt;br /&gt;
            entity =htmlentitydefs.name2codepoint[ref]&lt;br /&gt;
            self.handleUnicodeData(unichr(entity))&lt;br /&gt;
        except:&lt;br /&gt;
            try:&lt;br /&gt;
                handle_charref(ref) # deal with char-ref's missing the '#' (see Akma)&lt;br /&gt;
            except:&lt;br /&gt;
                self.handle_data(&amp;quot;&amp;amp;%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
    def handle_charref(self, ref):&lt;br /&gt;
        # called for each character reference, e.g. for &amp;quot;&amp;amp;#160;&amp;quot;, ref will be &amp;quot;160&amp;quot;&lt;br /&gt;
        # Reconstruct the original character reference.&lt;br /&gt;
        try:&lt;br /&gt;
            if ref[0]=='x':&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref[1:],16)))&lt;br /&gt;
            else:&lt;br /&gt;
                self.handleUnicodeData(unichr(int(ref)))&lt;br /&gt;
        except:&lt;br /&gt;
            self.handle_data(&amp;quot;&amp;amp;#%s&amp;quot; % ref)&lt;br /&gt;
&lt;br /&gt;
# called for each block of plain text, i.e. outside of any tag and&lt;br /&gt;
# not containing any character or entity references&lt;br /&gt;
    def handle_data(self, text):&lt;br /&gt;
        if type(text)==type(u' '):&lt;br /&gt;
            self.handleUnicodeData(text)&lt;br /&gt;
        if self.encoding== 'utf-8':&lt;br /&gt;
            try:&lt;br /&gt;
                uText = unicode(text,self.encoding) #utf-8 is pretty clear when it is wrong&lt;br /&gt;
            except:&lt;br /&gt;
                uText = unicode(text,'windows_1252','ignore') # and this is the likely wrongness&lt;br /&gt;
        else:&lt;br /&gt;
            uText = unicode(text,self.encoding,'replace') # if they have really broken encoding, (eg lots of shift-JIS blogs)&lt;br /&gt;
        self.handleUnicodeData(uText)&lt;br /&gt;
    def handleUnicodeData(self, uText):&lt;br /&gt;
        self.text.append(uText)&lt;br /&gt;
        &lt;br /&gt;
class xoxoParser(AttrParser):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        AttrParser.__init__(self)&lt;br /&gt;
        self.structs=[]&lt;br /&gt;
        self.xostack=[]&lt;br /&gt;
        self.textstack=['']&lt;br /&gt;
        self.attrparse = AttrParser()&lt;br /&gt;
    def normalize_attrs(self, attrs):&lt;br /&gt;
        attrs = [(k.lower(), self.attrparse.cleanText(v)) for k, v in attrs]&lt;br /&gt;
        attrs = [(k, k in ('rel','type') and v.lower() or v) for k, v in attrs]&lt;br /&gt;
        return attrs&lt;br /&gt;
    def setEncoding(self,encoding):&lt;br /&gt;
        AttrParser.setEncoding(self,encoding)&lt;br /&gt;
        self.attrparse.setEncoding(encoding)&lt;br /&gt;
    def pushStruct(self,struct):&lt;br /&gt;
        if type(struct) == type({}) and len(struct)==0 and len(self.structs) and type(self.structs[-1]) == type({}) and 'url' in self.structs[-1] and self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            self.xostack.append(self.structs[-1]) # put back the &amp;lt;a&amp;gt;-made one for extra def's&lt;br /&gt;
        else:&lt;br /&gt;
            self.structs.append(struct)&lt;br /&gt;
            self.xostack.append(self.structs[-1])&lt;br /&gt;
    def do_meta(self, attributes):&lt;br /&gt;
        atts = dict(self.normalize_attrs(attributes))&lt;br /&gt;
        #print atts.encode('utf-8')&lt;br /&gt;
        if 'http-equiv' in atts:&lt;br /&gt;
            if atts['http-equiv'].lower() == &amp;quot;content-type&amp;quot;:&lt;br /&gt;
                if 'content' in atts:&lt;br /&gt;
                    encoding = atts['content'].split('charset=')[-1]&lt;br /&gt;
                    self.setEncoding(encoding)&lt;br /&gt;
    def start_a(self,attrs):&lt;br /&gt;
        attrsD = dict(self.normalize_attrs(attrs))&lt;br /&gt;
        attrsD['url']= attrsD.get('href','')&lt;br /&gt;
        if 'href' in attrsD:&lt;br /&gt;
            del attrsD['href']&lt;br /&gt;
        self.pushStruct(attrsD)&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_a(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        if val: &lt;br /&gt;
            if self.xostack[-1].get('title','') == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if self.xostack[-1]['url'] == val:&lt;br /&gt;
                val=''&lt;br /&gt;
            if val:&lt;br /&gt;
                self.xostack[-1]['text']=val&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_dl(self,attrs):&lt;br /&gt;
        self.pushStruct({})&lt;br /&gt;
    def end_dl(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ol(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ol(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_ul(self,attrs):&lt;br /&gt;
        self.pushStruct([])&lt;br /&gt;
    def end_ul(self):&lt;br /&gt;
        self.xostack.pop()&lt;br /&gt;
    def start_li(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_li(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        while self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
        if type(val) == type(' ') or type(val) == type(u' '):&lt;br /&gt;
            self.xostack[-1].append(val)&lt;br /&gt;
    def start_dt(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dt(self):&lt;br /&gt;
        pass&lt;br /&gt;
    def start_dd(self,attrs):&lt;br /&gt;
        self.textstack.append('')&lt;br /&gt;
    def end_dd(self):&lt;br /&gt;
        val = self.textstack.pop()&lt;br /&gt;
        key = self.textstack.pop()&lt;br /&gt;
        if self.structs[-1] != self.xostack[-1]:&lt;br /&gt;
            val = self.structs.pop()&lt;br /&gt;
        self.xostack[-1][key]=val&lt;br /&gt;
    def handleUnicodeData(self, text):&lt;br /&gt;
        if len(self.stack) and containerTags.get(self.stack[-1],True): #skip text not within an element&lt;br /&gt;
            self.textstack[-1] += text&lt;br /&gt;
def toXOXO(struct,addHTMLWrapper=False,cssUrl=''):&lt;br /&gt;
    if type(struct) ==type((1,))or type(struct) ==type([1,]):&lt;br /&gt;
        inStruct = struct&lt;br /&gt;
    else:&lt;br /&gt;
        inStruct = [struct]&lt;br /&gt;
    if addHTMLWrapper:&lt;br /&gt;
        s= u'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;'''&lt;br /&gt;
        if cssUrl:&lt;br /&gt;
            s+=u'&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;%s&amp;quot;;&amp;lt;/style&amp;gt;' % cssUrl&lt;br /&gt;
        s+=u&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot; % makeXOXO(inStruct,'xoxo')&lt;br /&gt;
        return s.encode('utf-8')&lt;br /&gt;
    else:&lt;br /&gt;
        return makeXOXO(inStruct,'xoxo').encode('utf-8')&lt;br /&gt;
    &lt;br /&gt;
def fromXOXO(html):&lt;br /&gt;
    parser = xoxoParser()&lt;br /&gt;
    #parser.feed(unicode(html,'utf-8'))&lt;br /&gt;
    parser.feed(html)&lt;br /&gt;
    #print parser.structs&lt;br /&gt;
    structs=[struct for struct in parser.structs if struct]&lt;br /&gt;
    #print structs&lt;br /&gt;
    while len(structs) ==1 and type(structs)==type([1,]):&lt;br /&gt;
        structs=structs[0]&lt;br /&gt;
    return structs&lt;br /&gt;
&lt;br /&gt;
# Allow direct invocation&lt;br /&gt;
# Read HTML from URL, parse into data structures, then re-output&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
  if len(sys.argv) &amp;lt; 2: raise SystemExit(&amp;quot;Usage: &amp;quot;+sys.argv[0]+&amp;quot; url\n&amp;quot;+__doc__)&lt;br /&gt;
  url=sys.argv[1]&lt;br /&gt;
  file = urllib.urlopen(url)&lt;br /&gt;
  html=file.read(-1)&lt;br /&gt;
  file.close&lt;br /&gt;
  s=fromXOXO(html)&lt;br /&gt;
  p=toXOXO(s,True)&lt;br /&gt;
  print p&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== testxoxo.py  ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;testxoxo.py &lt;br /&gt;
Unit tests for xoxo.py&lt;br /&gt;
This file tests the functions in xoxo.py &lt;br /&gt;
The underlying model here is http://diveintopython.org/unit_testing/index.html &lt;br /&gt;
&lt;br /&gt;
run from command line with&lt;br /&gt;
python testxoxo.py -v&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import xoxo&lt;br /&gt;
reload(xoxo)&lt;br /&gt;
import unittest&lt;br /&gt;
&lt;br /&gt;
class xoxoTestCases(unittest.TestCase):&lt;br /&gt;
    &lt;br /&gt;
    def testSimpleList(self):&lt;br /&gt;
        '''make a xoxo file from a list'''&lt;br /&gt;
        l = ['1','2','3']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
    def testNestedList(self):&lt;br /&gt;
        '''make a xoxo file from a list with a list in'''&lt;br /&gt;
        l = ['1',['2','3']]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;1&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;2&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;3&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testDictionary(self):&lt;br /&gt;
        '''make a xoxo file from a dictionary'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;test&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;1&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;name&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Kevin&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testSingleItem(self):&lt;br /&gt;
        '''make a xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        self.assertEqual(html,'&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
&lt;br /&gt;
    def testWrapDiffers(self):&lt;br /&gt;
        '''make a xoxo file from a string with and without html wrapper and check they are different'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        htmlwrap =  xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.failIfEqual(html,htmlwrap)&lt;br /&gt;
&lt;br /&gt;
    def testWrapSingleItem(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True)&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testWrapItemWithCSS(self):&lt;br /&gt;
        '''make a wrapped xoxo file from a string'''&lt;br /&gt;
        l = &amp;quot;test&amp;quot;&lt;br /&gt;
        html = xoxo.toXOXO(l,addHTMLWrapper=True,cssUrl='reaptest.css')&lt;br /&gt;
        self.assertEqual(html,'''&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&lt;br /&gt;
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;&amp;lt;head profile=&amp;quot;&amp;quot;&amp;gt;&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=utf-8&amp;quot; /&amp;gt;&amp;lt;style type=&amp;quot;text/css&amp;quot; &amp;gt;@import &amp;quot;reaptest.css&amp;quot;;&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;test&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;''')&lt;br /&gt;
&lt;br /&gt;
    def testDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
        &lt;br /&gt;
    def testDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary wiht an url in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','name':'Kevin'}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)    &lt;br /&gt;
    def testNestedDictionaryRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with a dict in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':'1','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionaryWithURLRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testNestedDictionariesWithURLsRoundTrip(self):&lt;br /&gt;
        ''' make a dictionary with an url and a dict with an url into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'url':'http://example.com','inner':{'name':'Kevin','url':'http://slashdot.org'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
    def testListRoundTrip(self):&lt;br /&gt;
        ''' make a list into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3','2','1']&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofDictsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Dicts into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',{'a':'2'},{'b':'1','c':'4'}]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testListofListsRoundTrip(self):&lt;br /&gt;
        ''' make a list of Lists into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        l = ['3',['a','2'],['b',['1',['c','4']]]]&lt;br /&gt;
        html = xoxo.toXOXO(l)&lt;br /&gt;
        newdl= xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(l,newdl)&lt;br /&gt;
    def testDictofListsRoundTrip(self):&lt;br /&gt;
        ''' make a dict with lists in into a xoxo file and back again; check it is the same'''&lt;br /&gt;
        d = {'test':['1','2'],&lt;br /&gt;
        'name':'Kevin',&lt;br /&gt;
        'nestlist':['a',['b','c']],&lt;br /&gt;
        'nestdict':{'e':'6','f':'7'}}&lt;br /&gt;
        html = xoxo.toXOXO(d)&lt;br /&gt;
        newd = xoxo.fromXOXO(html)&lt;br /&gt;
        self.assertEqual(d,newd)&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInContainers(self):&lt;br /&gt;
        '''make sure text outside &amp;lt;li&amp;gt; etc is ignored'''&lt;br /&gt;
        d=xoxo.fromXOXO('&amp;lt;ol&amp;gt;bad&amp;lt;li&amp;gt;&amp;lt;dl&amp;gt;worse&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt; now&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(d,{'good': 'buy'})&lt;br /&gt;
&lt;br /&gt;
    def testXOXOjunkInElements(self):&lt;br /&gt;
        '''make sure text within &amp;lt;li&amp;gt; but outside a subcontainer is ignored'''&lt;br /&gt;
        l=xoxo.fromXOXO('&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;bad&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;good&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;buy&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;worse&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;bag&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;OK&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;fish&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;')&lt;br /&gt;
        self.assertEqual(l,[{'good': 'buy'},['OK']])&lt;br /&gt;
&lt;br /&gt;
    def testXOXOWithSpacesAndNewlines(self):&lt;br /&gt;
        '''unmung some xoxo with spaces in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        d2={'text':'item 1',&lt;br /&gt;
            'description':&amp;quot; This item represents the main point we're trying to make.&amp;quot;,&lt;br /&gt;
            'url':'http://example.com/more.xoxo',&lt;br /&gt;
            'title':'title of item 1',&lt;br /&gt;
            'type':'text/xml',&lt;br /&gt;
            'rel':'help'&lt;br /&gt;
            }&lt;br /&gt;
        xoxoAgain = xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        #this needs a smarter whitespace-sensitive comparison&lt;br /&gt;
        #self.assertEqual(xoxoSample,xoxoAgain)&lt;br /&gt;
&lt;br /&gt;
    def testSpecialAttributeDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class='xoxo'&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeAndDLDecoding(self):&lt;br /&gt;
        '''unmung some xoxo with &amp;lt;a href=' rel= etc in plus a &amp;lt;dl&amp;gt; in the same item and check result is right'''&lt;br /&gt;
        xoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&lt;br /&gt;
    &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;text&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;url&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;http://example.com/more.xoxo&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;title&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;title of item 1&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;type&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;text/xml&amp;lt;/dd&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;rel&amp;lt;/dt&amp;gt;&lt;br /&gt;
        &amp;lt;dd&amp;gt;help&amp;lt;/dd&amp;gt;&lt;br /&gt;
    &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d = xoxo.fromXOXO(xoxoSample)&lt;br /&gt;
        smartxoxoSample= '''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot;&lt;br /&gt;
         title=&amp;quot;title of item 1&amp;quot;&lt;br /&gt;
         type=&amp;quot;text/xml&amp;quot;&lt;br /&gt;
         rel=&amp;quot;help&amp;quot;&amp;gt;item 1&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;!-- note how the &amp;quot;text&amp;quot; property is simply the contents of the &amp;lt;a&amp;gt; element --&amp;gt;&lt;br /&gt;
      &amp;lt;dl&amp;gt;&lt;br /&gt;
        &amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&lt;br /&gt;
          &amp;lt;dd&amp;gt; This item represents the main point we're trying to make.&amp;lt;/dd&amp;gt;&lt;br /&gt;
      &amp;lt;/dl&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;'''&lt;br /&gt;
        d2 = xoxo.fromXOXO(smartxoxoSample)&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
    def testSpecialAttributeEncode(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        expectedHTML= '&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://example.com/more.xoxo&amp;quot; title=&amp;quot;sample url&amp;quot; rel=&amp;quot;help&amp;quot; type=&amp;quot;text/xml&amp;quot; &amp;gt;an example&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;' &lt;br /&gt;
        self.assertEqual(html,expectedHTML)&lt;br /&gt;
        &lt;br /&gt;
    def testSpecialAttributeRoundTripFull(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help','text':'an example'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoText(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo','title':'sample url','type':&amp;quot;text/xml&amp;quot;,'rel':'help'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testSpecialAttributeRoundTripNoTextOrTitle(self):&lt;br /&gt;
        '''check it makes an &amp;lt;a href with a url parameter and no text or title attribute'''&lt;br /&gt;
        d={'url':'http://example.com/more.xoxo'}&lt;br /&gt;
        html=xoxo.toXOXO(d)&lt;br /&gt;
        self.assertEqual(d,xoxo.fromXOXO(html))&lt;br /&gt;
    def testAttentionRoundTrip(self):&lt;br /&gt;
        '''check nested &amp;lt;a&amp;gt; and &amp;lt;dl&amp;gt; and &amp;lt;a&amp;gt; are preserved'''&lt;br /&gt;
        kmattn='''&amp;lt;ol class=&amp;quot;xoxo&amp;quot;&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.boingboing.net/&amp;quot; title=&amp;quot;Boing Boing Blog&amp;quot; &amp;gt;Boing Boing Blog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://boingboing.net/rss.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Boing Boing Blog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/&amp;quot; title=&amp;quot;Financial Cryptography&amp;quot; &amp;gt;Financial Cryptography&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://www.financialcryptography.com/mt/index.rdf&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;Financial Cryptography&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/&amp;quot; title=&amp;quot;HubLog&amp;quot; &amp;gt;HubLog&amp;lt;/a&amp;gt;&amp;lt;dl&amp;gt;&amp;lt;dt&amp;gt;alturls&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/index.xml&amp;quot; &amp;gt;xmlurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://hublog.hubmed.org/foaf.rdf&amp;quot; &amp;gt;foafurl&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/dd&amp;gt;&amp;lt;dt&amp;gt;description&amp;lt;/dt&amp;gt;&amp;lt;dd&amp;gt;HubLog&amp;lt;/dd&amp;gt;&amp;lt;/dl&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;''';&lt;br /&gt;
        d = xoxo.fromXOXO(kmattn)&lt;br /&gt;
        newattn = xoxo.toXOXO(d)&lt;br /&gt;
        d2 = xoxo.fromXOXO(newattn)&lt;br /&gt;
        self.assertEqual(newattn,xoxo.toXOXO(d2))&lt;br /&gt;
        self.assertEqual(d,d2)&lt;br /&gt;
        self.assertEqual(kmattn,newattn)&lt;br /&gt;
        &lt;br /&gt;
    def testUnicodeRoundtrip(self):&lt;br /&gt;
        '''check unicode characters can go to xoxo and back'''&lt;br /&gt;
        src=unicode('Tantek \xc3\x87elik and a snowman \xe2\x98\x83','utf-8')&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html))&lt;br /&gt;
    def testUtf8Roundtrip(self):&lt;br /&gt;
        '''check utf8 characters can go to xoxo and back'''&lt;br /&gt;
        src='Tantek \xc3\x87elik and a snowman \xe2\x98\x83'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('utf-8'))&lt;br /&gt;
    def testWindows1252Roundtrip(self):&lt;br /&gt;
        '''check 1252 characters can go to xoxo and back'''&lt;br /&gt;
        src='This is an evil\xa0space'&lt;br /&gt;
        html = xoxo.toXOXO(src)&lt;br /&gt;
        self.assertEqual(src,xoxo.fromXOXO(html).encode('windows-1252'))&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    unittest.main()&lt;br /&gt;
else:&lt;br /&gt;
    runner = unittest.TextTestRunner()&lt;br /&gt;
    suite = unittest.makeSuite(xoxoTestCases,'test')&lt;br /&gt;
    runner.run(suite)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Newacct</name></author>
	</entry>
</feed>