123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
/*******************************************************************************

        Copyright: Copyright (C) 2008 Kris Bell.  All rights reserved.

        License:   BSD style: $(LICENSE)

        version:   Initial release: March 2008      

        Authors:   Kris

*******************************************************************************/

module tango.text.xml.DocTester;

private import tango.core.Exception;

private import tango.text.xml.Document;

private import tango.text.convert.Format;

private import tango.core.Vararg;

/*******************************************************************************

        Validate a document

        TODO: add various tests here, or in subclasses, as required

*******************************************************************************/

protected class DocTester(T)
{
        private alias Document!(T) Doc;         /// the typed document
        private alias Doc.Node     Node;        /// generic document node

        /***********************************************************************
        
                Generate a text representation of the document tree

        ***********************************************************************/
        
        final void validate (Doc doc)
        {     
                validate (doc.elements);  
        }
        
        /***********************************************************************
        
                Generate a representation of the given node-subtree 

        ***********************************************************************/
        
        final void validate (Node node)
        {
                switch (node.id)
                       {
                       case XmlNodeType.Document:
                            foreach (n; node.children)
                                     validate (n);
                            break;
        
                       case XmlNodeType.Element:
                            element (node);

                            foreach (n; node.attributes)
                                     attribute (n);

                            foreach (n; node.children)
                                     validate (n);
                            break;
        
                       case XmlNodeType.Attribute:
                            attribute (node);
                            break;
        
                       case XmlNodeType.Data:
                            data (node);
                            break;
        
                       case XmlNodeType.Comment:
                            comment (node);
                            break;
        
                       case XmlNodeType.PI:
                            pi (node);
                            break;
                
                       case XmlNodeType.CData:
                            cdata (node);
                            break;
                
                       case XmlNodeType.Doctype:
                            doctype (node);
                            break;
                       }
        }

        /***********************************************************************
        
                validate an element

        ***********************************************************************/
        
        void element (Node node)
        {
                uniqueAttrNames (node);
        }

        /***********************************************************************
        
                validate an attribute

        ***********************************************************************/
        
        void attribute (Node node)
        {
        }

        /***********************************************************************
        
                validate a data node

        ***********************************************************************/
        
        void data (Node node)
        {
        }

        /***********************************************************************
        
                validate a comment node

        ***********************************************************************/
        
        void comment (Node node)
        {
        }

        /***********************************************************************
        
                validate a pi node

        ***********************************************************************/
        
        void pi (Node node)
        {
        }

        /***********************************************************************
        
                validate a cdata node

        ***********************************************************************/
        
        void cdata (Node node)
        {
        }

        /***********************************************************************
        
                validate a doctype node

        ***********************************************************************/
        
        void doctype (Node node)
        {
        }

        /***********************************************************************
        
                Ensure attribute names are unique within the element 

        ***********************************************************************/
        
        static void uniqueAttrNames (Node node)
        {
                T[128]  name1 = void,
                        name2 = void;

                // non-optimal, but is it critical?
                foreach (attr; node.attributes)
                        {
                        auto name = attr.name (name1);
                        auto next = attr.nextSibling;
                        while (next !is null)
                              {
                              if (name == next.name(name2))
                                  error ("duplicate attribute name '{}' for element '{}'", 
                                          name, node.name(name2));
                              next = attr.nextSibling;
                              }
                        }
        }

        /***********************************************************************
        
                halt validation

        ***********************************************************************/
        
        static void error (const(char)[] format, ...)
        {
                throw new TextException (Format.convert(_arguments, _argptr, format).idup);
        }
}




/*******************************************************************************

*******************************************************************************/

debug (DocTester)
{
        void main()
        {
                auto v = new DocTester!(char);
        }
}