# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is Komodo code.
#
# The Initial Developer of the Original Code is ActiveState Software Inc.
# Portions created by ActiveState Software Inc are Copyright (C) 2000-2007
# ActiveState Software Inc. All Rights Reserved.
#
# Contributor(s):
#   ActiveState Software Inc
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****

import time
import re
from cElementTree import TreeBuilder, XMLParser, Element
import logging
log = logging.getLogger("koXMLTreeService")
# log.setLevel(logging.INFO)


class recollector:
    def __init__(self):
        self.res = {}
        self.regs = {}

    def add(self, name, reg, mods=None):
        self.regs[name] = reg % self.regs
        # print "%s = %s" % (name, self.regs[name])
        if mods:
            self.res[name] = re.compile(self.regs[
                                        name], mods)  # check that it is valid
        else:
            self.res[name] = re.compile(self.regs[
                                        name])  # check that it is valid

collector = recollector()
a = collector.add

a("S", "[ \\n\\t\\r]+")
a("NameStrt", "[A-Za-z_:]|[^\\x00-\\x7F]")
a("NameChar", "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]")
a("Name", "(?:%(NameStrt)s)(?:%(NameChar)s)*")
a("AttValSE", "\"[^<\"]*\"|'[^<']*'")
a("attrfinderRE", "(?:[\n \t]*)(%(Name)s)(?:%(S)s)?=(?:%(S)s)?(%(AttValSE)s)")
a("namespaces",
  'xmlns(?::(?P<prefix>\w+))?=(?P<ns>(?:")([^"]*?)(?:")|(?:\')([^\']*?)(?:\'))', re.S | re.U)
a("tagpart",
  '(?:<(?![?!-/>\s]))((?:(?P<prefix>[^\s/>]+):)?(?P<name>[^:\s/>]+)?)(?:\s+(?P<data>[^/<>]*))?', re.S | re.U)
a("tags", '<!--.*?-->|%(tagpart)s(?:/)?>', re.S | re.U)
a("alltags", '<!--.*?-->|(<[^\[!>?-].*?>)', re.S | re.U)
a("QuoteSE", "\"[^\"]*\"|'[^']*'")
a("DOCTYPE",
  r'<!DOCTYPE\s+(?P<type>\S+)\s+(?P<ident>PUBLIC|SYSTEM)\s+(?P<data1>%(QuoteSE)s)\s*(?P<data2>%(QuoteSE)s)?\s*(?:\[|>)', re.S)


def getdoctype(text):
    doctype = None
    regex = collector.res["DOCTYPE"]
    m = regex.search(text)
    if m:
        m = m.groupdict()
        # [1:-1] is to strip quotes
        if m['data1']:
            m['data1'] = m['data1'][1:-1]
        if m['data2']:
            m['data2'] = m['data2'][1:-1]
        if m['ident'] == 'PUBLIC':
            doctype = (m['type'], m['ident'], m['data1'], m['data2'])
        else:
            doctype = (m['type'], m['ident'], "", m['data1'])
    return doctype


def getattrs(text):
    attrs = {}
    regex = collector.res["attrfinderRE"]
    match = regex.findall(text)
    for a in match:
        if a[1]:
            attrs[a[0]] = a[1][1:-1]
        else:
            attrs[a[0]] = ""
    return attrs


def currentTag(text):
    m = collector.res["tagpart"].search(text)
    if not m:
        return None
    td = m.groupdict()
    ad = {}
    if td['data']:
        ad.update(getattrs(td['data']))
    return (td['prefix'], td['name'], ad, m.start(0))


def elementFromTag(tree, tag, parent=None):
    tagName = tag[1]
    if not tagName:
        tagName = ""
    ns = None
    if tag[0]:
        if tag[0] in tree.prefixmap:
            ns = tree.prefixmap[tag[0]]
        else:
            nsattr = "xmlns:%s" % tag[0]
            if nsattr in tag[2]:
                ns = tag[2][nsattr]
                del tag[2][nsattr]
                tree.prefixmap[tag[0]] = ns
    elif "xmlns" in tag[2]:
        ns = tag[2]["xmlns"]
        del tag[2]["xmlns"]
    elif parent is not None:
        ns = parent.ns
    localName = tag
    if ns:
        tagName = "{%s}%s" % (ns, tagName)
    elem = Element(tagName, tag[2])
    try:
        elem.start = tree.err_info
        elem.end = None
    except:
        # will happen when parsing with cElementTree
        pass
    # print elem.localName
    if parent is not None:
        parent.append(elem)
    tree.nodemap[elem] = parent
    tree.nodes.append(elem)
    if elem.ns is not None:
        if elem.ns not in tree.tags:
            tree.tags[elem.ns] = {}
        tree.tags[elem.ns][elem.localName] = elem
    return elem


def elementFromText(tree, text, parent=None):
    current = currentTag(text)
    if current:
        return elementFromTag(tree, current, parent)
    return None


class iterparse:
    """iterparse that catches syntax errors so we can still handle any
    events that happen prior to the syntax error"""
    def __init__(self, content, events=("start", "end", "start-ns", "end-ns")):
        self.content = content
        self._events = events
        self.err = None
        self.err_info = None
        self.root = None

    def __iter__(self):
        events = []
        b = TreeBuilder()
        p = XMLParser(b)
        p._setevents(events, self._events)
        try:
            p.feed(self.content)
        except SyntaxError as e:
            self.err = e
            self.err_info = (
                p.CurrentLineNumber, p.CurrentColumnNumber, p.CurrentByteIndex)

        for event in events:
            yield event
        del events[:]
        try:
            self.root = p.close()
        except SyntaxError as e:
            # if we had a previous syntax error, keep it
            if not self.err:
                self.err = e
                self.err_info = (
                    p.CurrentLineNumber, p.CurrentColumnNumber, p.CurrentByteIndex)
        for event in events:
            yield event


def bisect_left_nodes_start(a, x, lo=0, hi=None):
    """A version of bisect.bisect_left which compares nodes based on their start position.
    """
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # print "comparing", a[mid].start[:2], "and", x
        if a[mid].start is None:
            return mid
        if a[mid].start[:2] == x: return mid
        if a[mid].start[:2] < x: lo = mid+1
        else:
            hi = mid
    return lo


class XMLDocument(object):

    def __init__(self, content=None):
        self.content = content
        self.reset()
        if self.content:
            self.getDoctype()

    def getDoctype(self):
        self.doctype = getdoctype(self.content)
        if self.doctype:
            self.publicId = self.doctype[2]
            self.systemId = self.doctype[3]

    def reset(self):
        self.doctype = None
        self.publicId = None
        self.systemId = None
        self.err = None
        self.err_info = None
        self.root = None
        self.current = None

        self._rootnodes = []
        self.nodes = []  # flat list of all nodes
        self.tags = {}  # { namespace_uri: { tag_local_name: elem, ...} , ...}
        self.nodemap = {}  # {child_elem: parent_elem, ... }
        self.namespaces = []  # flat list of namespace uri's
        self.nsmap = {}  # { "http:/...": "xslt", ... }
        self.prefixmap = {}  # { "xslt": "http://.....", ... }

    def getRoots(self):
        # return a list of all nodes that have no parent
        if not self._rootnodes:
            self._rootnodes = [
                node for node in self.nodemap if self.nodemap[node] is None]
        return self._rootnodes

    def namespace(self, elem):
        # print "%s:%s xmlns[%s]"%(self.prefix(elem),elem.localName,elem.ns)
        if hasattr(elem, "ns") and elem.ns:
            return elem.ns
        return self.nsmap.get("")

    def parent(self, elem):
        return self.nodemap.get(elem)

    def qname(self, name):
        if name and name[0] == '{':
            ns, ln = name[1:].split('}')
            prefix = self.nsmap.get(ns)
            if prefix:
                return "%s:%s" % (prefix, ln)
            return ln
        return name

    def isAncestorOf(self, node, child):
        """ Return true if child is a descendant of node """
        # print "asking if %r is an ancestor of %r" %( node, child)
        currentParent = self.parent(child)
        while currentParent != child and currentParent is not None:
            # print "\tparent =", currentParent
            if node == currentParent:
                # print "-->is a parent"
                return True
            currentParent = self.parent(currentParent)
        # print "-->isn't a parent"
        return False

    def locateNode(self, line, col):
        # nodes are 1-indexed, so we need to switch our indexing scheme
        line += 1

        # first look for the last node to start at or before the current
        # position
        idx = bisect_left_nodes_start(self.nodes, (line, col))-1
        if idx < 0:
            if self.nodes:
                return self.nodes[0]
            return None
        assert idx < len(self.nodes)
        node = self.nodes[idx]
        # that was easy.  Now we may need to move up the parent chain
        # from this node if we are past the end of a node but before
        # the beginning of another, e.g.  <foo><bar>asd</bar>|</foo>
        # -- the right node is foo, but the current value of node is 'bar'
        startPos = node.start[:2]
        if startPos is None:  # if we're in a partial node, that's it
            return node
        if startPos[:2] == (line, col):  # if it's an exact match, that's it
            return node
        # if idx == 0: return node # if we're at the toplevel, so be it
        while node is not None:
            while node.end:
                # move up the parent chain until you get a parent
                # whose end is after the current location
                last_line, last_col = node.end[:2]
                if (last_line, last_col) < (line, col):
                    node = self.parent(node)
                    if node is None:
                        return node
                    continue
                break

            if node is not None and not node.end:
                # check it's parents and see if they have end markers
                pnode = self.parent(node)
                while pnode:
                    if pnode.end:
                        last_line, last_col = pnode.end[:2]
                        if (last_line, last_col) < (line, col):
                            node = pnode
                            break
                    pnode = self.parent(pnode)
                if node.end:
                    continue
            break

        return node

    def prefixFromNS(self, ns):
        if self.prefixmap.get("") == ns:
            return ""
        prefix = self.nsmap.get(ns)
        if not prefix:
            prefix = self.nsmap.get(self.root.ns)
        return prefix

    def prefix(self, elem):
        if not hasattr(elem, "ns") or not elem.ns:
            return ""
        return self.prefixFromNS(elem.ns)

    def tagname(self, elem):
        prefix = self.prefix(elem)
        if prefix:
            return "%s:%s" % (prefix, elem.localName)
        return elem.localName

    _endtagRe = re.compile(r"(</(\w+:)?\w+>)", re.U)

    def parse(self, content=None):
        self.reset()
        self.content = content
        if content:
            # first, find the doctype decl
            self.getDoctype()
        elif not self.content:
            raise Exception("no content to parse")

        elstack = [None]
        self.current = None
        tags = {}
        last_pos_ok = None
        iter = iterparse(self.content)
        for event, elem in iter:
            if event == "start":
                # print "%r %r %d %d %d" % (event, elem, elem.start[0],
                # elem.start[1], elem.start[2])
                self.nodemap[elem] = self.current
                self.nodes.append(elem)
                if elem.ns not in self.tags:
                    self.tags[elem.ns] = {}
                self.tags[elem.ns][elem.localName] = elem
                elstack.append(elem)
                self.current = elem
            elif event == "end":
                # print "%r %r %r %r" % (event, elem, elem.start, elem.end)
                if elem.end:
                    try:
                        pos = elem.end[2]
                        # print "  len %d pos %d" % (len(self.content), pos)
                        # put the end location at the end of the end tag
                        m = self._endtagRe.match(self.content[pos:])
                        if m and m.groups():
                            pos = pos + m.end(1)
                            if pos > 0:
                                # we want to be after the ">"
                                diff = pos - elem.end[2] + 1
                                elem.end = (elem.end[
                                            0], elem.end[1] + diff, pos)
                    except IndexError as e:
                        # XXX FIXME BUG 56337
                        log.exception(e)
                        pass
                node = elstack.pop()
                if elstack[-1] is None:
                    self._rootnodes.append(node)
                self.current = elstack[-1]
            elif event == "start-ns":
                self.namespaces.append(elem)
                self.prefixmap[elem[0]] = elem[1]
                self.nsmap[elem[1]] = elem[0]
            elif event == "end-ns":
                self.namespaces.pop()
        self.root = iter.root
        self.err = iter.err
        self.err_info = iter.err_info
        # set the root if we can
        if self.root is None and self.nodes:
            self.root = self.nodes[0]
        self.end_error(self.content)
        # if we still do not have a root, do it
        # now, as we should have a node
        if self.root is None and self.nodes:
            self.root = self.nodes[0]
        # release content
        self.content = None

    def end_error(self, content):
        if not self.err_info:
            return
        if not content:
            raise Exception("No content?")
        # create an element for the last part of the parse
        parent = self.current
        if self.err_info[2] >= 0:
            start = self.err_info[2]
        else:
            # slower
            # print self.err_info
            p = 0
            for i in range(self.err_info[0] - 1):
                # use re.search("\r|\n|\r\n")
                p = content.find("\n", p + 1)
            start = p + self.err_info[1] + 1
        end = content.find("<", start+1)
        if end <= start:
            end = len(content)
        # fixup the start position
        start = content.rfind(">", 0, start) + 1
        if start >= end:
            return
        # print self.err_info
        # print content[start:end]
        current = currentTag(content[start:end])
        if not current:
            return

        # print "%s:%s %r %d" % current
        # fix error info
        start = start+current[3]
        line = content.count('\n', 0, start)
        col = start - content.rfind('\n', 0, start)
        self.err_info = (line, col, start)
        self.current = elem = elementFromTag(self, current, parent)

    def dump(self):
        print("error ", self.err)
        print("error_info ", self.err_info)
        print("%d nodes created" % len(self.nodemap))
        print("doctype ", self.doctype)
        print("publicId ", self.publicId)
        print("systemId ", self.systemId)
        print(self.prefixmap)
        print(self.nsmap)
        print("root ", self.root)
        if self.root:
            print("root tag ", self.root.tag)
            print("root ns ", self.root.ns)
            print("root localName ", self.root.localName)
            print("root start ", self.root.start)
            print("root end ", self.root.end)
        print("tree.current ", self.current)

import HTMLTreeParser


class HTMLDocument(XMLDocument):

    def parse(self, content=None):
        if content:
            self.reset()
            self.content = content
            # first, find the doctype decl
            self.getDoctype()
        elif not self.content:
            raise Exception("no content to parse")

        p = HTMLTreeParser.Parser(HTMLTreeParser.HTMLTreeBuilder())
        p.feed(content)
        self.root = p.close()
        self.nodes = p._builder.nodes
        self.nodemap = p._builder.nodemap
        self._rootnodes = p._builder._rootnodes
        self.current = p._builder.current


class TreeService:
    __treeMap = {}  # map uri to elementtree

    def __init__(self):
        pass

    def treeFromCache(self, uri):
        if uri in self.__treeMap:
            # print "tree cache hit for [%s]"%uri
            return self.__treeMap[uri]
        return None

    def getTreeForURI(self, uri, content=None):
        if not uri and not content:
            return None
        tree = None
        if uri and uri in self.__treeMap:
            tree = self.__treeMap[uri]
            # if tree is not None:
            #    print "tree cache hit for [%s]"%uri
            if not content:
                return tree

        if not tree:
            if not content:
                # get the content
                try:
                    f = open(uri, 'r')
                    content = f.read(-1)
                    f.close()
                except IOError as e:
                    # ignore file errors and return an empty tree
                    content = ""
            if not content.startswith("<?xml"):
                tree = HTMLDocument()
            if not tree:
                tree = XMLDocument()
                # raise Exception("NOT IMPLEMENTED YET")
        if content:
            tree.parse(content)
        if uri:
            self.__treeMap[uri] = tree
        return tree

    def getTreeForContent(self, content):
        return self.getTreeForURI(None, content)


__treeservice = None


def getService():
    global __treeservice
    if not __treeservice:
        __treeservice = TreeService()
    return __treeservice

if __name__ == "__main__":
    import sys
    # basic logging configuration
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    # set a format which is simpler for console use
    formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
    # tell the handler to use this format
    console.setFormatter(formatter)
    # add the handler to the root logger
    logging.getLogger('').addHandler(console)

    bigfile = "/Users/shanec/main/Apps/Komodo-devel/test/bigfile.xml"
    fn = "/Users/shanec/main/Apps/Komodo-devel/src/samples/xslt_sample.xsl"
    from elementtree.ElementTree import tostring

    if 0:
        # fn = "/Users/shanec/main/Apps/Komodo-devel/src/install/wix/feature-
        # core.wxs"
        t1 = time.clock()
        tree = getService().getTreeForURI(bigfile)
        t2 = time.clock()
        print("cElementTree took ", (t2-t1))
        tree.dump()

    if 0:
        f = open(bigfile, 'r')
        content = f.read(-1)
        f.close()
        t1 = time.clock()
        tree = HTMLDocument()
        tree.parse(content)
        t2 = time.clock()
        print("HTMLBuilder took ", (t2-t1))

    if 0:
        print(currentTag("<xsl"))
        print(currentTag("<xsl:"))
        print(currentTag("<xsl:tag"))
        print(currentTag("text><xsl:tag"))
        # print nodemap

    html = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
"""
    tree = getService().getTreeForURI("Text.html", html)
    #print(tostring(tree.root))

    html = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<HEAD>
 <TITLE>Mozilla Cross-Reference</TITLE>
 <link HREF=http://www.activestate.com/global.css rel="stylesheet" type="text/css">
</HEAD>
<BODY   BGCOLOR="#FFFFFF" TEXT="#000000"
	LINK="#0000EE" VLINK="#551A8B" ALINK="#FF0000">

<table width="100%" border="0" cellspacing="0" cellpadding="0">
  <tr>
    <td>
      <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td width="145"><a href=http://www.activestate.com/index.html><img src=http://www.activestate.com/img/Main_Logo_Border.gif width="167" height="66" border="0" alt="ActiveState Tool Corp."></a></td>
          <td bgcolor="#000000" colspan=2 width="90%" align="center"><img src=http://www.activestate.com/img/Main_Banner.gif alt="Programming for the People."></td>
        </tr>
      </table>
      <table width="100%" bgcolor="#000000" border="0" cellpadding="0" cellspacing="0">
 <tr>
  <td width="600">
    <table width="600" border="0" cellpadding="0" cellspacing="3">
     <tr>
       <td class="mainnav" bgcolor="#C2B266" width="100" align="center"><a href=http://www.activestate.com/Products/index.html>Products</a></td>
       <td class="mainnav" bgcolor="#C2B266" width="100" align="center"><a href=http://www.activestate.com/Support/index.html>Support</a></td>
       <td class="mainnav" bgcolor="#C2B266" width="100" align="center"><a href=http://www.activestate.com/Corporate/index.html>About Us</a></td>
       <td class="mainnav" bgcolor="#C2B266" width="100" align="center"><a href=http://www.activestate.com/Contact_Us.html>Contact</a></td>
       <td class="mainnav" bgcolor="#C2B266" width="100" align="center"><a href=http://www.activestate.com/Site_Map.html>Site Map</a></td>
     </tr>
    </table>
   </td>
   <td class="mainnav" width="100%">
     <table width="100%" border="0" cellpadding="0" cellspacing="0">
       <tr>
         <td class="mainnav" bgcolor="#C2B266" width="100%">&nbsp;</td>
         <td class="mainnav" bgcolor="#000000" width="3">&nbsp;</td>
       </tr>
     </table>
  </td>
 </tr>
</table>
</td>
</tr>
</table>

<I>$treename</I>
<P>

"""
    tree = getService().getTreeForURI("Text.html", html)
    #print(tostring(tree.root))

    html = """<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
    <BODY>

        <FORM><FIELDSET ><SELECT class=""><OPTGROUP >

"""
    tree = getService().getTreeForContent(html)

    tree = getService().getTreeForURI("newfile.txt", "")
    tree = getService().getTreeForURI("newfile.txt", "<html>")
    tree = getService().getTreeForURI("newfile.txt", "<html> <")
    node = tree.locateNode(tree.current.start[0], tree.current.start[1])
    assert node == tree.current, "locateNode returned incorrect node"

    tree = getService().getTreeForURI("newfile.txt", "<table></table>\n\n\n\n")
    node = tree.locateNode(2, 0)
    assert node is None, "locateNode returned incorrect node"
    node = tree.locateNode(0, 7)
    assert node is not None, "locateNode returned incorrect node"
    sys.exit(0)

    xml = """
<c1><c2 a1="1" a2='1' a3='val'><e1 /><e2 f1="1" f2 = '33' /><c3 a='1'>blah</c3></c2  >  </"""
    tree = getService().getTreeForContent(xml)
    node = tree.locateNode(tree.current.start[0], tree.current.start[1])
    assert node == tree.current, "locateNode returned incorrect node"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xxmlns="xyz" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
<xsl:template match="Class">
    <html> <xsl:apply-imports/>
    <xsl:
            <xsl:apply-templates select="Order"/>
    </html>
</xsl:template>
"""
    tree = getService().getTreeForContent(xml)
    node = tree.locateNode(tree.current.start[0], tree.current.start[1])
    assert node == tree.current, "locateNode returned incorrect node"

    # ensure we get the correct current node
    xml = """<?xml version="1.0"?>
<!DOCTYPE window PUBLIC "-//MOZILLA//DTD XUL V1.0//EN" "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <popupset id="editorTooltipSet">
        <popup type="tooltip" id="editorTooltip" flex="1">
            <description multiline="true" id="editorTooltip-tooltipText" class="tooltip-label" flex="1"/>
        </popup><
        <popup type="autocomplete" id="popupTextboxAutoComplete"/>
    </popupset>

"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "popupset", "current element is incorrect"

    # ensure we get the correct current node
    xml = """<?xml version="1.0"?>
<!DOCTYPE window PUBLIC "-//MOZILLA//DTD XUL V1.0//EN" "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    <popupset id="editorTooltipSet">
        <popup type="tooltip" id="editorTooltip" flex="1">
            <description multiline="true" id="editorTooltip-tooltipText" class="tooltip-label" flex="1"/>
        </popup> <
        <popup type="autocomplete" id="popupTextboxAutoComplete"/>
    </popupset>

"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "popupset", "current element is incorrect"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <

  <xsl:template/>
"""
    tree = getService().getTreeForContent(xml)
    assert tree.current == tree.root, "current element is incorrect"
    assert tree.current.localName == "stylesheet", "current element is incorrect"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.tag == "{http://www.w3.org/1999/XSL/Transform}", "current element is incorrect"
    assert tree.current.localName == "", "current element is incorrect"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "stylesheet", "current element is incorrect"

    xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html """

    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "html", "current element is incorrect"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template
"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "template", "current element is incorrect"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/><xsl:template"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "template", "current element is incorrect"

    xml = """<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:

  <xsl:template/>
"""
    tree = getService().getTreeForContent(xml)
    assert tree.current.localName == "", "current element is incorrect"
    assert tree.current.tag == "{http://www.w3.org/1999/XSL/Transform}", "current element is incorrect"

    html = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><body><p><ul><li><li><li></ul></body>
"""
    tree = getService().getTreeForContent(html)
    # print tostring(tree.root)
    assert tree.current.localName == "html", "current element is incorrect"

    html = """<!DOCTYPE h:html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<h:html xmlns:h='urn:test'"""
    tree = getService().getTreeForContent(html)
    # print tostring(tree.root)
    assert tree.current.localName == "html", "current element is incorrect"

    # from cElementTree import Element
    # tag = u"{urn:test}test"
    # print tag
    # e = Element(tag, {})
    # print e.localName
    # print e.tag

    xml = """<?xml version="1.0" encoding="UTF-8"?>
<!-- This sample XML file shows you ... -->

<Class>
<Order Name="TINAMIFORMES">
        <Family Name="TINAMIDAE">
            <Species attr="value">content.</Species>
            <![CDATA[
                This is a CDATA section
            ]]>
        </Family>
    </Order>
"""
    tree = getService().getTreeForContent(xml)
    # print tostring(tree.root)
    assert len(tree.root[0][0][0]) == 0, "bad parent/child relationship"

    xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <body
        <!-- a comment -->
    <title>
    </title>
</html>
"""

    tree = getService().getTreeForContent(xml)
    # print tostring(tree.root)
    assert tree.current.localName == "body", "current element is incorrect"
    assert tree.parent(
        tree.current).localName == "html", "current element is incorrect"

    xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html
    <body
"""

    tree = getService().getTreeForContent(xml)
    # print tostring(tree.root)
    assert tree.current.localName == "html", "current element is incorrect"
