183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# ElementTree
383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# $Id: ElementInclude.py 3375 2008-02-13 08:05:08Z fredrik $
483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# limited xinclude support for element trees
683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# history:
883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-08-15 fl   created
983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# 2003-11-14 fl   fixed default loader
1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (c) 2003-2004 by Fredrik Lundh.  All rights reserved.
1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# fredrik@pythonware.com
1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# http://www.pythonware.com
1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# --------------------------------------------------------------------
1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# The ElementTree toolkit is
1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Copyright (c) 1999-2008 by Fredrik Lundh
2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# By obtaining, using, and/or copying this software and/or its
2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# associated documentation, you agree that you have read, understood,
2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# and will comply with the following terms and conditions:
2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Permission to use, copy, modify, and distribute this software and
2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# its associated documentation for any purpose and without fee is
2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# hereby granted, provided that the above copyright notice appears in
2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# all copies, and that both that copyright notice and this permission
2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# notice appear in supporting documentation, and that the name of
3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Secret Labs AB or the author not be used in advertising or publicity
3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# pertaining to distribution of the software without specific, written
3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# prior permission.
3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# OF THIS SOFTWARE.
4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# --------------------------------------------------------------------
4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Licensed to PSF under a Contributor Agreement.
4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# See http://www.python.org/psf/license for licensing details.
4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh##
4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Limited XInclude support for the ElementTree package.
4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh##
5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport copy
5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom . import ElementTree
5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehXINCLUDE = "{http://www.w3.org/2001/XInclude}"
5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehXINCLUDE_INCLUDE = XINCLUDE + "include"
5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehXINCLUDE_FALLBACK = XINCLUDE + "fallback"
5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh##
6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Fatal include error.
6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass FatalIncludeError(SyntaxError):
6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    pass
6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh##
6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Default loader.  This loader reads an included resource from disk.
6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param href Resource reference.
6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param parse Parse mode.  Either "xml" or "text".
7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param encoding Optional text encoding.
7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @return The expanded resource.  If the parse mode is "xml", this
7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#    is an ElementTree instance.  If the parse mode is "text", this
7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#    is a Unicode string.  If the loader fails, it can return None
7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#    or raise an IOError exception.
7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @throws IOError If the loader fails to load the resource.
7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef default_loader(href, parse, encoding=None):
7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    file = open(href)
7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    if parse == "xml":
8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        data = ElementTree.parse(file).getroot()
8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    else:
8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        data = file.read()
8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if encoding:
8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            data = data.decode(encoding)
8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    file.close()
8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return data
8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh##
8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Expand XInclude directives.
9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#
9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param elem Root element.
9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @param loader Optional resource loader.  If omitted, it defaults
9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#     to {@link default_loader}.  If given, it should be a callable
9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#     that implements the same interface as <b>default_loader</b>.
9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @throws FatalIncludeError If the function fails to include a given
9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh#     resource, or if the tree contains malformed XInclude elements.
9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# @throws IOError If the function fails to load a given resource.
9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef include(elem, loader=None):
10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    if loader is None:
10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        loader = default_loader
10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # look for xinclude elements
10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    i = 0
10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    while i < len(elem):
10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        e = elem[i]
10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if e.tag == XINCLUDE_INCLUDE:
10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # process xinclude directive
10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            href = e.get("href")
10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            parse = e.get("parse", "xml")
11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if parse == "xml":
11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                node = loader(href, parse)
11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if node is None:
11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    raise FatalIncludeError(
11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        "cannot load %r as %r" % (href, parse)
11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        )
11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                node = copy.copy(node)
11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if e.tail:
11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    node.tail = (node.tail or "") + e.tail
11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                elem[i] = node
12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            elif parse == "text":
12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                text = loader(href, parse, e.get("encoding"))
12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if text is None:
12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    raise FatalIncludeError(
12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        "cannot load %r as %r" % (href, parse)
12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        )
12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if i:
12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    node = elem[i-1]
12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    node.tail = (node.tail or "") + text + (e.tail or "")
12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                else:
13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    elem.text = (elem.text or "") + text + (e.tail or "")
13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                del elem[i]
13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                raise FatalIncludeError(
13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    "unknown parse type in xi:include tag (%r)" % parse
13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                )
13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif e.tag == XINCLUDE_FALLBACK:
13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            raise FatalIncludeError(
13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                "xi:fallback tag must be child of xi:include (%r)" % e.tag
14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                )
14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            include(e, loader)
14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        i = i + 1
144