Orb/python/orb/guidiser.py
changeset 2 932c358ece3e
child 4 468f4c8d3d5b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Orb/python/orb/guidiser.py	Fri Apr 23 20:45:58 2010 +0100
@@ -0,0 +1,613 @@
+# Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved.
+# This component and the accompanying materials are made available under the terms of the License 
+# "Eclipse Public License v1.0" which accompanies this distribution, 
+# and is available at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+from __future__ import with_statement
+import unittest
+import uuid
+import os
+import stat
+import sys
+import shutil
+import xml
+import logging
+from optparse import OptionParser, check_choice
+from xml.etree import ElementTree as etree
+from cStringIO import StringIO
+from lib import scan, xml_decl, doctype_identifier, XmlParser
+from doxyidredirect import DoxyIdRedirect, ExceptionDoxyIdRedirectLookup
+
+
+__version__ = "0.1"
+
+class Guidiser(object):
+    """
+    A simple class that parses an xml file and converts the values of all
+    id, href and keyref attributes to a 'GUID'.
+    
+    >>> guid = Guidiser()
+    >>> root = guid.guidise(StringIO(cxxclass))
+    >>> oldroot = etree.parse(StringIO(cxxclass)).getroot()
+    >>> oldroot.attrib['id']
+    'CP_class'
+    >>> root.attrib['id']
+    'GUID-25825EC4-341F-3EA4-94AA-7DCE380E6D2E'
+    """
+    # Publishing targets
+    PT_MODE = 0
+    PT_DITAOT = 1
+    PUBLISHING_TARGETS = (PT_MODE, PT_DITAOT)
+    
+    def __init__(self, namespace='www.nokia.com', publishing_target=0, xmlparser=XmlParser(), doxyidredirect=DoxyIdRedirect(None)):
+        self.namespace = self._get_namespace(namespace)
+        self.set_publishing_target(publishing_target)
+        self.xmlparser = xmlparser
+        self.doxyidredirect = doxyidredirect
+        
+    def set_publishing_target(self, target):
+        if not target in self.PUBLISHING_TARGETS:
+            raise Exception('Invalid Publishing Target \"%s\"' % target)
+        self._publishing_target = target
+        
+    def get_publishing_target(self):
+        return self._publishing_target
+        
+    def _get_namespace(self, namespace, LEN_BYTES=16):
+        if len(namespace) < LEN_BYTES:
+            namespace = namespace + (' ' * (LEN_BYTES - len(namespace)))
+        return uuid.UUID(bytes=namespace[:LEN_BYTES])
+    
+    def _get_guid(self, fqn):
+        return ('GUID-%s' % (uuid.uuid3(self.namespace, fqn))).upper()
+                        
+    def _guidise_href(self, href, tag):
+        if tag == "xref":
+            return self._guidise_xref_href(href)
+        else:
+            # Tag is a topicref or topicref descended element
+            return self._guidise_topicref_href(href)
+    
+    def _guidise_topicref_href(self, href):
+        # Guidise an href that points to a ditamap
+        # NOTE: the id of the map is assumed to be the same as the filename
+        # (minus the ".ditamap" extension)
+        if href.endswith(".ditamap"):
+            guid = self._get_guid(href[:-len(".ditamap")])
+            if self.get_publishing_target() == self.PT_DITAOT:
+                guid += ".ditamap"
+            return guid
+        
+        # Guidise an href that points to a topic
+        # NOTE: Doxygen currently outputs "filepath#topicid" for topicref hrefs
+        # the "#topicid" is redundant (as topicrefs can't reference below the topic level)
+        # so will probably be removed from doxygen output at some point.
+        filename = href.split('#')[0]
+        id = os.path.splitext(filename)[0]
+        fqn = None
+        if not(id.lower() in ("test", "deprecated", "todo") or id.lower().find("namespace_") != -1):                
+            try:
+                filename, fqn = self.doxyidredirect.lookupId(id)
+            except ExceptionDoxyIdRedirectLookup, err:
+                logging.error("Could not lookup Fully Qualified APIName for id '%s' in href '%s'" % (id, href))
+        #if the id was not found just guidise the id
+        #this is just to make the id unique for mode
+        guid = self._get_guid(fqn) if fqn else self._get_guid(id)
+        if self.get_publishing_target() == self.PT_DITAOT:
+            guid+=".xml"
+        return guid
+    
+    def _guidise_xref_href(self, href):
+        # Don't guidise references without hashes. Assume they are filepaths
+        # to files other than ditatopics
+        if href.find('#') == -1:
+            return href
+			
+        # Doxygen currently outputs hrefs in the format autolink_8cpp.xml#autolink_8cpp_1ae0e289308b6d2cbb5c86e753741981dc
+        # The right side of the # is not enough to extract the fully qualified name of the function because it is md5ed
+        # Send the right side to doxyidredirect to get the fqn of the function			
+        filename, id = href.split('#')
+        fqn = None                
+        if not(id.lower() in ("test", "deprecated", "todo") or id.lower().find("namespace_") != -1):                        
+            try:
+                fqn = self.doxyidredirect.lookupId(id)[1]
+            except ExceptionDoxyIdRedirectLookup, err:
+                logging.error("No API name for element id %s, guidising id instead" % id)
+
+        guid = self._get_guid(fqn) if fqn else self._get_guid(id)
+        basename, ext = os.path.splitext(filename)
+        try:
+            base_guid = self._get_guid(self.doxyidredirect.lookupId(basename)[1])
+        except ExceptionDoxyIdRedirectLookup, e:
+            base_guid = self._get_guid(basename)
+            
+        if self.get_publishing_target() == self.PT_DITAOT:
+            return base_guid + ext + "#" + guid
+        else:
+            return guid
+    
+    def _guidise_id(self, id):
+        try:
+            filename, fqn = self.doxyidredirect.lookupId(id)
+            return self._get_guid(fqn)
+        except ExceptionDoxyIdRedirectLookup, err:
+            logging.debug("Didn't find a Fully Qualified APIName for id '%s'" % id)
+            return self._get_guid(id)
+    
+    def guidise(self, xmlfile):
+        #WORKAROUND: ElementTree provides no function to set prefixes and makes up its own if they are not set (ns0, ns1, ns2)
+        etree._namespace_map["http://dita.oasis-open.org/architecture/2005/"] = 'ditaarch'
+        try:
+            root = etree.parse(xmlfile).getroot()
+        except xml.parsers.expat.ExpatError, e:
+            logging.error("%s could not be parsed: %s\n" % (xmlfile, str(e)))
+            return None
+        for child in root.getiterator():
+            for key in [key for key in ('id', 'href', 'keyref') if key in child.attrib]:
+                if key == 'id':
+                    child.attrib['id'] = self._guidise_id(child.attrib['id'])
+                elif key == 'href':
+                    if 'format' in child.attrib and child.attrib['format'] == 'html':
+                        continue
+                    else:
+                        base_dir = os.path.dirname(xmlfile) if isinstance(xmlfile, str) else ""
+                        child.attrib['href'] = self._guidise_href(child.attrib['href'], child.tag)
+                elif key == 'keyref':
+                    child.attrib['keyref'] = self._get_guid(child.attrib['keyref'])                    
+
+        return root
+    
+
+def updatefiles(xmldir, publishing_target="ditaot"):
+    publishing_target = Guidiser.PT_MODE if (publishing_target == "mode") else Guidiser.PT_DITAOT
+    guidiser = Guidiser(publishing_target=publishing_target, doxyidredirect=DoxyIdRedirect(xmldir))
+    for filepath in scan(xmldir):
+        logging.debug('Guidising file \"%s\"' % filepath)
+        root = guidiser.guidise(filepath)
+        if root is not None:
+            try:
+                os.chmod(filepath, stat.S_IWRITE)
+            except Exception, e:
+                logging.error("Could not make file \"%s\" writable, error was \"%s\"" % (filepath, e))
+                continue            
+            with open(filepath, 'w') as f:
+                f.write(xml_decl()+'\n')
+                try:
+                    doc_id = doctype_identifier(root.tag)
+                except Exception, e:
+                    logging.error("Could not write doctype identifier for file \"%s\", error was \"%s\""
+                                  %(filepath, e))
+                else:
+                    f.write(doc_id+'\n')
+                f.write(etree.tostring(root))        
+                f.close()
+                
+def main():
+    usage = "usage: %prog [options] <Path to the XML content>"
+    parser = OptionParser(usage, version='%prog ' + __version__)
+    parser.add_option("-p", dest="publishing_target", type="choice", choices=["mode", "ditaot"], default="mode", 
+                      help="Publishing Target: mode|ditaot, [default: %default]")
+    parser.add_option("-l", "--loglevel", type="int", default=30, help="Log Level (debug=10, info=20, warning=30, [error=40], critical=50)")      
+    (options, args) = parser.parse_args()
+    if len(args) < 1:
+        parser.print_help()
+        parser.error("Please supply the path to the XML content")
+    if options.loglevel:
+        logging.basicConfig(level=options.loglevel)  
+    updatefiles(args[0], options.publishing_target)
+
+
+if __name__ == '__main__':
+    sys.exit(main())
+
+    
+######################################
+# Test code
+######################################
+
+class StubDoxyIdRedirect(object):
+    def __init__(self, theDir):
+        self.dict = {'struct_e_sock_1_1_t_addr_update':('struct_e_sock_1_1_t_addr_update.xml', 'ESock::TAddrUpdate'),
+        'class_c_active_scheduler_1_1_t_cleanup_bundle':('class_c_active_scheduler_1_1_t_cleanup_bundle.xml', 'CActiveScheduler::TCleanupBundle'),
+        'class_test':('class_test.xml', 'Test'),
+        'class_test_1a99f2bbfac6c95612322b0f10e607ebe5':('cxxclass.xml', 'Test')}
+    
+    def lookupId(self, doxy_id):
+        try:
+            filename, fqn = self.dict[doxy_id]
+            return (filename, fqn)
+        except Exception, e:
+            raise ExceptionDoxyIdRedirectLookup("StubException: %s" % e)
+
+
+class TestGuidiser(unittest.TestCase):
+    def setUp(self):
+        self.guidiser = Guidiser(publishing_target=Guidiser.PT_MODE, doxyidredirect=StubDoxyIdRedirect('adir'))
+        self.test_dir = "guidiser_test_dir"
+        
+    def _create_test_data(self):
+        f = open("struct_e_sock_1_1_t_addr_update.xml", "w")
+        f.write(struct_e_sock_1_1_t_addr_update)
+        f.close()
+        os.mkdir(self.test_dir)
+        f = open(os.path.join(self.test_dir, "struct_e_sock_1_1_t_addr_update.xml"), "w")
+        f.write(struct_e_sock_1_1_t_addr_update)
+        f.close()        
+        
+    def _cleanup_test_data(self):
+        os.remove("struct_e_sock_1_1_t_addr_update.xml")
+        shutil.rmtree(self.test_dir)
+        
+    def test_i_can_get_and_set_a_PT(self):
+        self.assertEqual(self.guidiser.get_publishing_target(), Guidiser.PT_MODE)
+        self.guidiser.set_publishing_target(Guidiser.PT_DITAOT)
+        self.assertEqual(self.guidiser.get_publishing_target(), Guidiser.PT_DITAOT)
+        
+    def test_i_raise_an_exception_when_trying_to_set_an_invalid_PT(self):
+        self.assertRaises(Exception, self.guidiser.set_publishing_target, 2) 
+        
+    def test_i_update_root_elements_id(self):        
+        root = self.guidiser.guidise(StringIO(cxxclass))
+        self.assertEqual(root.attrib['id'], "GUID-56866D87-2CE9-31EA-8FA7-F4275FDBCB93")
+
+    def test_i_continue_if_passed_an_invalid_file(self):
+        try:
+            self.guidiser.guidise(StringIO("<cxxclass><argh</cxxclass>"))
+        except Exception:
+            self.fail("I shouldnt have raised an exception")
+
+    def _test_keys_were_converted(self, key):
+        root = self.guidiser.guidise(StringIO(cxxclass))
+        for child in root.getiterator():
+            if key in child.attrib:
+                self.assertTrue(child.attrib[key].startswith('GUID'))        
+
+    def test_i_update_a_subelements_id(self):
+        self._test_keys_were_converted('id')
+
+    def test_i_update_all_hrefs_with_a_guid(self):
+        self._test_keys_were_converted('href')
+
+    def test_i_update_all_keyrefs_with_a_guid(self):
+        self._test_keys_were_converted('keyref')
+                
+    def test_based_fqn_and_one_param(self):
+        self.assertTrue(self.guidiser._get_guid("RConnection::EnumerateConnections(TUint&)") ==
+                        "GUID-18F9018F-78DE-3A7E-8363-B7CB101E7A99" 
+                       )
+        
+    def test_based_fqn_and_muiltiple_params(self):
+        self.assertTrue(self.guidiser._get_guid("RConnection::ProgressNotification(TSubConnectionUniqueId, TNifProgressBuf&, TRequestStatus&, TUint)") ==
+                        "GUID-6E7005CF-4D8E-31CE-BAEA-21965ACC9C17" 
+                       )
+        
+    def test_based_fqn_and_muiltiple_params_ones_a_default(self):
+        self.assertTrue(self.guidiser._get_guid("RConnection::Open(RSocketServ& aSocketServer, TUint aConnectionType = KConnectionTypeDefault)") ==
+                        "GUID-CE8F3FE7-14F2-3FB6-B04C-8596B5F80DFC" 
+                       )
+                
+    def test_based_fqn_and_muiltiple_params_ones_templated(self):
+        self.assertTrue(self.guidiser._get_guid("RConnection::DataReceivedNotificationRequest(TSubConnectionUniqueId, TUint, TPckg<TUint>&, TRequestStatus&)") ==
+                        "GUID-9E056551-22C2-3F85-8E3D-C11FA3B46F07" 
+                       )
+        
+    def test_based_toplevel_class(self):
+        self.assertTrue(self.guidiser._get_guid("RConnection") ==
+                        "GUID-BED8A733-2ED7-31AD-A911-C1F4707C67FD" 
+                       )
+        
+    def test_target_id(self):
+        self.assertTrue(self.guidiser._get_guid("ESock::TAddrUpdate") ==
+                         "GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B"
+                         )
+        
+    def test_topicref_href_to_topic_for_mode(self):
+        self.assertEquals(self.guidiser._guidise_href("struct_e_sock_1_1_t_addr_update.xml#struct_e_sock_1_1_t_addr_update", "topicref"),
+                 "GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B"
+                 )
+        
+    def test_topicref_href_to_topic_for_ditaot(self):
+        self.guidiser.set_publishing_target(Guidiser.PT_DITAOT)
+        self._create_test_data()
+        try:
+            self.assertEquals(self.guidiser._guidise_href("struct_e_sock_1_1_t_addr_update.xml#struct_e_sock_1_1_t_addr_update", "topicref"),
+                              "GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B.xml")
+        finally:
+            self._cleanup_test_data()
+
+                        
+    def test_topicref_href_to_map_for_mode(self):
+        self.assertEquals(self.guidiser._guidise_href("ziplib.ditamap", "topicref"),
+                 "GUID-7C7A889C-AE2B-31FC-A5DA-A87019E1251D"
+                 )
+        
+    def test_topicref_href_to_map_for_ditaot(self):
+        self.guidiser.set_publishing_target(Guidiser.PT_DITAOT)
+        self.assertEquals(self.guidiser._guidise_href("ziplib.ditamap", "topicref"),
+                 "GUID-7C7A889C-AE2B-31FC-A5DA-A87019E1251D.ditamap"
+                 )
+                
+    def test_xref_href_to_topic_in_same_file_for_mode(self):
+        self.assertEquals(self.guidiser._guidise_href("struct_e_sock_1_1_t_addr_update.xml#struct_e_sock_1_1_t_addr_update", "xref"),
+                 "GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B"
+                 )
+
+    def test_xref_href_to_topic_in_same_file_for_ditaot(self):
+        self.guidiser.set_publishing_target(Guidiser.PT_DITAOT)
+        self.assertEquals(self.guidiser._guidise_href("struct_e_sock_1_1_t_addr_update.xml#struct_e_sock_1_1_t_addr_update", "xref"),
+                 "GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B.xml#GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B"
+                 )
+				 
+    def test_xref_href_to_some_other_file_on_file_system(self):
+        self.guidiser.set_publishing_target(Guidiser.PT_DITAOT)
+        self.assertEquals(self.guidiser._guidise_href("../../documentation/RFCs/rfc3580.txt", "xref"),
+                 "../../documentation/RFCs/rfc3580.txt"
+                 )
+    
+    def test_i_guidise_the_id_of_a_fully_qualified_apiname(self):
+        self.assertEquals(self.guidiser._guidise_id("struct_e_sock_1_1_t_addr_update"),
+         "GUID-E72084E6-C1CE-3388-93F7-5B7A3F506C3B"
+         )
+         
+    def test_id_guidise_the_id_something_that_is_not_a_fully_qualified_apiname(self):
+        self.assertEquals(self.guidiser._guidise_id("commsdataobjects"),
+         "GUID-2F2463E0-6C84-3FAB-8B60-57E57315FDEB"
+         )
+         
+    def test_i_preserve_namespaces(self):  
+        xml_in = """<reference ditaarch:DITAArchVersion="1.1" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" />"""
+        xml_expected = """<reference ditaarch:DITAArchVersion="1.1" xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" />"""
+        root = self.guidiser.guidise(StringIO(xml_in))
+        self.assertEqual(etree.tostring(root), xml_expected)
+        
+class Testupdate_files(unittest.TestCase):
+    
+    def setUp(self):
+        self.test_dir = "guidisertestdata"
+        
+    def tearDown(self):
+        shutil.rmtree(self.test_dir)
+    
+    def test_i_can_update_a_file_on_the_file_sys(self):
+        def reference_file_handle(mode):
+            return open(os.path.join(self.test_dir, "reference.dita"), mode) 
+        os.mkdir(self.test_dir)
+        f = reference_file_handle("w")
+        f.write(filesys_cxxclass)
+        f.close()
+        updatefiles(self.test_dir)
+        self.assertEquals(reference_file_handle("r").read(), filesys_cxxclass_guidised)
+        
+struct_e_sock_1_1_t_addr_update = """<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<!DOCTYPE cxxStruct PUBLIC "-//NOKIA//DTD DITA C++ API Struct Reference Type v0.1.0//EN" "dtd/cxxStruct.dtd" >
+<cxxStruct id="struct_coord_struct">
+	<apiName>CoordStruct</apiName>
+	<shortdesc/>
+	<cxxStructDetail>
+		<cxxStructDefinition>
+			<cxxStructAccessSpecifier value="public"/>
+			<cxxStructAPIItemLocation>
+				<cxxStructDeclarationFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/restypedef.cpp"/>
+				<cxxStructDeclarationFileLine name="lineNumber" value="10"/>
+				<cxxStructDefinitionFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/restypedef.cpp"/>
+				<cxxStructDefinitionFileLineStart name="lineNumber" value="9"/>
+				<cxxStructDefinitionFileLineEnd name="lineNumber" value="15"/>
+			</cxxStructAPIItemLocation>
+		</cxxStructDefinition>
+		<apiDesc>
+			<p>A coordinate pair. </p>
+		</apiDesc>
+	</cxxStructDetail>
+	<cxxVariable id="struct_coord_struct_1a183d7226fc5a8470ce9b9f04f9cb69bb">
+		<apiName>x</apiName>
+		<shortdesc/>
+		<cxxVariableDetail>
+			<cxxVariableDefinition>
+				<cxxVariableAccessSpecifier value="public"/>
+				<cxxVariableDeclaredType>float</cxxVariableDeclaredType>
+				<cxxVariableScopedName>CoordStruct</cxxVariableScopedName>
+				<cxxVariablePrototype>float x</cxxVariablePrototype>
+				<cxxVariableNameLookup>CoordStruct::x</cxxVariableNameLookup>
+				<cxxVariableAPIItemLocation>
+					<cxxVariableDeclarationFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/restypedef.cpp"/>
+					<cxxVariableDeclarationFileLine name="lineNumber" value="12"/>
+				</cxxVariableAPIItemLocation>
+			</cxxVariableDefinition>
+			<apiDesc>
+				<p>The x coordinate </p>
+			</apiDesc>
+		</cxxVariableDetail>
+	</cxxVariable>
+	<cxxVariable id="struct_coord_struct_1a1a5966a881bc3e76e9becf00639585ac">
+		<apiName>y</apiName>
+		<shortdesc/>
+		<cxxVariableDetail>
+			<cxxVariableDefinition>
+				<cxxVariableAccessSpecifier value="public"/>
+				<cxxVariableDeclaredType>float</cxxVariableDeclaredType>
+				<cxxVariableScopedName>CoordStruct</cxxVariableScopedName>
+				<cxxVariablePrototype>float y</cxxVariablePrototype>
+				<cxxVariableNameLookup>CoordStruct::y</cxxVariableNameLookup>
+				<cxxVariableAPIItemLocation>
+					<cxxVariableDeclarationFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/restypedef.cpp"/>
+					<cxxVariableDeclarationFileLine name="lineNumber" value="14"/>
+				</cxxVariableAPIItemLocation>
+			</cxxVariableDefinition>
+			<apiDesc>
+				<p>The y coordinate </p>
+			</apiDesc>
+		</cxxVariableDetail>
+	</cxxVariable>
+</cxxStruct>"""
+        
+filesys_cxxclass = """<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.1.0//EN" "dtd/cxxClass.dtd" >
+<cxxClass id="class_c_active_scheduler_1_1_t_cleanup_bundle">
+    <apiName>CActiveScheduler::TCleanupBundle</apiName>
+    <shortdesc/>
+    <cxxClassDetail>
+        <cxxClassDefinition>
+            <cxxClassAccessSpecifier value="private"/>
+            <cxxClassAPIItemLocation>
+                <cxxClassDeclarationFile name="filePath" value="K:/epoc32/include/e32base.h"/>
+                <cxxClassDeclarationFileLine name="lineNumber" value="2832"/>
+                <cxxClassDefinitionFile name="filePath" value="K:/sf/os/commsfw/datacommsserver/esockserver/csock/CS_CLI.CPP"/>
+                <cxxClassDefinitionFileLineStart name="lineNumber" value="2831"/>
+                <cxxClassDefinitionFileLineEnd name="lineNumber" value="2836"/>
+            </cxxClassAPIItemLocation>
+        </cxxClassDefinition>
+        <apiDesc/>
+    </cxxClassDetail>
+    <cxxVariable id="class_c_active_scheduler_1_1_t_cleanup_bundle_1aaa7a637534aa0b9164dda2816be6fbf4">
+        <apiName>iCleanupPtr</apiName>
+        <shortdesc/>
+        <cxxVariableDetail>
+            <cxxVariableDefinition>
+                <cxxVariableAccessSpecifier value="public"/>
+                <cxxVariableDeclaredType>
+                    <apiRelation keyref="class_c_cleanup">CCleanup</apiRelation> *</cxxVariableDeclaredType>
+                <cxxVariableScopedName>CActiveScheduler::TCleanupBundle</cxxVariableScopedName>
+                <cxxVariablePrototype>CCleanup * iCleanupPtr</cxxVariablePrototype>
+                <cxxVariableNameLookup>CActiveScheduler::TCleanupBundle::iCleanupPtr</cxxVariableNameLookup>
+                <cxxVariableAPIItemLocation>
+                    <cxxVariableDeclarationFile name="filePath" value="K:/epoc32/include/e32base.h"/>
+                    <cxxVariableDeclarationFileLine name="lineNumber" value="2834"/>
+                </cxxVariableAPIItemLocation>
+            </cxxVariableDefinition>
+            <apiDesc/>
+        </cxxVariableDetail>
+    </cxxVariable>
+    <cxxVariable id="class_c_active_scheduler_1_1_t_cleanup_bundle_1ad750b8dbf966def2486a52b6c3d236fc">
+        <apiName>iDummyInt</apiName>
+        <shortdesc/>
+        <cxxVariableDetail>
+            <cxxVariableDefinition>
+                <cxxVariableAccessSpecifier value="public"/>
+                <cxxVariableDeclaredType>
+                    <apiRelation keyref="_c_s___c_l_i_8_c_p_p_1abb88f5378e8305d934297176fe5fa298">TInt</apiRelation>
+                </cxxVariableDeclaredType>
+                <cxxVariableScopedName>CActiveScheduler::TCleanupBundle</cxxVariableScopedName>
+                <cxxVariablePrototype>TInt iDummyInt</cxxVariablePrototype>
+                <cxxVariableNameLookup>CActiveScheduler::TCleanupBundle::iDummyInt</cxxVariableNameLookup>
+                <cxxVariableAPIItemLocation>
+                    <cxxVariableDeclarationFile name="filePath" value="K:/epoc32/include/e32base.h"/>
+                    <cxxVariableDeclarationFileLine name="lineNumber" value="2835"/>
+                </cxxVariableAPIItemLocation>
+            </cxxVariableDefinition>
+            <apiDesc/>
+        </cxxVariableDetail>
+    </cxxVariable>
+</cxxClass>"""
+
+filesys_cxxclass_guidised = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.1.0//EN" "dtd/cxxClass.dtd">
+<cxxClass id="GUID-83FD90ED-B2F7-3ED5-ABC5-83ED6A3F1C2F">
+    <apiName>CActiveScheduler::TCleanupBundle</apiName>
+    <shortdesc />
+    <cxxClassDetail>
+        <cxxClassDefinition>
+            <cxxClassAccessSpecifier value="private" />
+            <cxxClassAPIItemLocation>
+                <cxxClassDeclarationFile name="filePath" value="K:/epoc32/include/e32base.h" />
+                <cxxClassDeclarationFileLine name="lineNumber" value="2832" />
+                <cxxClassDefinitionFile name="filePath" value="K:/sf/os/commsfw/datacommsserver/esockserver/csock/CS_CLI.CPP" />
+                <cxxClassDefinitionFileLineStart name="lineNumber" value="2831" />
+                <cxxClassDefinitionFileLineEnd name="lineNumber" value="2836" />
+            </cxxClassAPIItemLocation>
+        </cxxClassDefinition>
+        <apiDesc />
+    </cxxClassDetail>
+    <cxxVariable id="GUID-903F7E6D-EFFE-3A37-9348-B9FE3A27AF4A">
+        <apiName>iCleanupPtr</apiName>
+        <shortdesc />
+        <cxxVariableDetail>
+            <cxxVariableDefinition>
+                <cxxVariableAccessSpecifier value="public" />
+                <cxxVariableDeclaredType>
+                    <apiRelation keyref="GUID-3BB23EB1-2F65-378D-918B-1FBBD6E46C90">CCleanup</apiRelation> *</cxxVariableDeclaredType>
+                <cxxVariableScopedName>CActiveScheduler::TCleanupBundle</cxxVariableScopedName>
+                <cxxVariablePrototype>CCleanup * iCleanupPtr</cxxVariablePrototype>
+                <cxxVariableNameLookup>CActiveScheduler::TCleanupBundle::iCleanupPtr</cxxVariableNameLookup>
+                <cxxVariableAPIItemLocation>
+                    <cxxVariableDeclarationFile name="filePath" value="K:/epoc32/include/e32base.h" />
+                    <cxxVariableDeclarationFileLine name="lineNumber" value="2834" />
+                </cxxVariableAPIItemLocation>
+            </cxxVariableDefinition>
+            <apiDesc />
+        </cxxVariableDetail>
+    </cxxVariable>
+    <cxxVariable id="GUID-DA4580F4-EBCC-3FA2-A856-810EAFC82236">
+        <apiName>iDummyInt</apiName>
+        <shortdesc />
+        <cxxVariableDetail>
+            <cxxVariableDefinition>
+                <cxxVariableAccessSpecifier value="public" />
+                <cxxVariableDeclaredType>
+                    <apiRelation keyref="GUID-1A4B29B0-5E06-39E5-A0A8-4A33E093C872">TInt</apiRelation>
+                </cxxVariableDeclaredType>
+                <cxxVariableScopedName>CActiveScheduler::TCleanupBundle</cxxVariableScopedName>
+                <cxxVariablePrototype>TInt iDummyInt</cxxVariablePrototype>
+                <cxxVariableNameLookup>CActiveScheduler::TCleanupBundle::iDummyInt</cxxVariableNameLookup>
+                <cxxVariableAPIItemLocation>
+                    <cxxVariableDeclarationFile name="filePath" value="K:/epoc32/include/e32base.h" />
+                    <cxxVariableDeclarationFileLine name="lineNumber" value="2835" />
+                </cxxVariableAPIItemLocation>
+            </cxxVariableDefinition>
+            <apiDesc />
+        </cxxVariableDetail>
+    </cxxVariable>
+</cxxClass>"""
+        
+cxxclass = """<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.1.0//EN" "dtd/cxxClass.dtd" >
+<cxxClass id="class_test">
+	<apiName>Test</apiName>
+	<shortdesc/>
+	<cxxClassDetail>
+		<cxxClassDefinition>
+			<cxxClassAccessSpecifier value="public"/>
+			<cxxClassAPIItemLocation>
+				<cxxClassDeclarationFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/autolink.cpp"/>
+				<cxxClassDeclarationFileLine name="lineNumber" value="59"/>
+				<cxxClassDefinitionFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/autolink.cpp"/>
+				<cxxClassDefinitionFileLineStart name="lineNumber" value="58"/>
+				<cxxClassDefinitionFileLineEnd name="lineNumber" value="74"/>
+			</cxxClassAPIItemLocation>
+		</cxxClassDefinition>
+		<apiDesc>
+        <p>Points to function <xref href="class_test.xml#class_test_1a99f2bbfac6c95612322b0f10e607ebe5">Test()</xref></p>
+		</apiDesc>
+	</cxxClassDetail>
+	<cxxFunction id="class_test_1a99f2bbfac6c95612322b0f10e607ebe5">
+		<apiName>Test</apiName>
+		<shortdesc/>
+		<cxxFunctionDetail>
+			<cxxFunctionDefinition>
+				<cxxFunctionAccessSpecifier value="public"/>
+				<cxxFunctionConstructor/>
+				<cxxFunctionDeclaredType/>
+				<cxxFunctionScopedName>Test</cxxFunctionScopedName>
+				<cxxFunctionPrototype>Test()</cxxFunctionPrototype>
+				<cxxFunctionNameLookup>Test::Test()</cxxFunctionNameLookup>
+				<cxxFunctionParameters/>
+				<cxxFunctionAPIItemLocation>
+					<cxxFunctionDeclarationFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/autolink.cpp"/>
+					<cxxFunctionDeclarationFileLine name="lineNumber" value="61"/>
+					<cxxFunctionDefinitionFile name="filePath" value="C:/wip/sysdoc/tools/Doxygen/branches/DITA/test/PaulRo/linking/src/autolink.cpp"/>
+					<cxxFunctionDefinitionFileLineStart name="lineNumber" value="77"/>
+					<cxxFunctionDefinitionFileLineEnd name="lineNumber" value="77"/>
+				</cxxFunctionAPIItemLocation>
+			</cxxFunctionDefinition>
+			<apiDesc>
+				<p>details. </p>
+			</apiDesc>
+		</cxxFunctionDetail>
+	</cxxFunction>
+</cxxClass>""" 
\ No newline at end of file