########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Xml/MarkupWriter.py,v 1.2 2005/03/11 18:26:56 uogbuji Exp $
"""
MarkupWriter provides a very friendly interface for generating XML content

Copyright 2005 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

import sys
from Ft.Xml import XML_NAMESPACE, EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE

class MarkupWriter(object):
    """
    General-purpose utility class for generating XML (may eventually be
    expanded to produce more output types)

    Sample usage:
    
    from Ft.Xml import MarkupWriter
    writer = MarkupWriter(indent=u"yes")
    writer.startDocument()
    writer.startElement(u'xsa')
    writer.startElement(u'vendor')
    #Element with simple text (#PCDATA) content
    writer.simpleElement(u'name', content=u'Centigrade systems')
    #Note writer.text(content) still works
    writer.simpleElement(u'email', content=u"info@centigrade.bogus")
    writer.endElement(u'vendor')
    #Element with an attribute
    writer.startElement(u'product', attributes={u'id': u"100\u00B0"})
    #Note writer.attribute(name, value, namespace=None) still works
    writer.simpleElement(u'name', content=u"100\u00B0 Server")
    #XML fragment
    writer.xmlFragment('<version>1.0</version><last-release>20030401</last-release>')
    #Empty element
    writer.simpleElement(u'changes')
    writer.endElement(u'product')
    writer.endElement(u'xsa')
    writer.endDocument()

    Note on the difference between 4Suite writers and printers
    Writer  - module that exposes a broad public API for building output
              bit by bit
    Printer - module that simply takes a DOM and creates output from it
              as a whole, within one API invokation
    """
    def __init__(self, stream=sys.stdout, **wargs):
        """
        Convenience factory function for Markup writers (based on
        xsl:output in XSLT)
        """
        from Ft.Xml.Xslt.XmlWriter import XmlWriter
        from Ft.Xml.Xslt.OutputParameters import OutputParameters
        oparams = OutputParameters()
        for arg in wargs:
            setattr(oparams, arg, wargs[arg])
        self.writer = XmlWriter(oparams, stream)
        return

    def __getattr__(self, value):
        #Delegate to writer
        #if hasattr(self, value):
        #    return object.self.__dict, value)
        return getattr(self.writer, value)
        
    def startElement(self, tagName, namespace=EMPTY_NAMESPACE, extraNss=None,
                     attributes=None):
        """
        Create a start tag with optional attributes.  Must eventually
        be matched with an endElement call
        
        tagName - qualified name of the element (must be unicode)
        namespace - optional namespace URI
        attribute - optional dictionary mapping name to unicode value
                    the name can either be a unicode QName or a tuple
                    of (QName, namespace URI)
        """
        self.writer.startElement(tagName, namespace, extraNss)
        if attributes is not None:
            for name in attributes:
                if isinstance(name, tuple):
                    name, namespace = name
                    value = attributes[name]
                    self.writer.attribute(name, value, namespace)
                else:
                    value = attributes[name]
                    self.writer.attribute(name, value)
        return

    def simpleElement(self, tagName, namespace=EMPTY_NAMESPACE, extraNss=None,
                      attributes=None, content=u""):
        """
        Create a simple tag with optional attributes and content.  The
        complete element, start tag, optional text content, end tag, will
        all be generated by this one call.  Must *not* be matched with
        an endElement call
        
        tagName - qualified name of the element (must be unicode)
        namespace - optional namespace URI
        attribute - optional dictionary mapping name to unicode value
                    the name can either be a unicode QName or a tuple
                    of (QName, namespace URI)
        content   - optional unicode object with the text body of the
                    simple element
        """
        self.startElement(tagName, namespace, extraNss, attributes)
        if content:
            self.writer.text(content)
        self.writer.endElement(tagName, namespace)
        return

    def xmlFragment(self, fragment):
        """
        Incorporate a well-formed general entity into the output.
        fragment of
        fragment - string (must not be a Unicode object) to be incorporated
                   verbatim into the output, after testing for wellp-formedness
        """
        from Ft.Xml.Domlette import EntityReader
        #Essentially just a WF test.
        #We don't actually use the resulting docfrag
        docfrag = EntityReader.parseString(
            fragment, 'urn:bogus:Ft.Xml.Xslt.MarkupWriter.xmlFragment')
        self.writer._stream.write(fragment)
        return


