diff -r cb04c94014ea Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py Thu Jun 26 01:36:47 2014 +0200 +++ b/Lib/test/test_xml_etree.py Thu Jun 26 01:09:24 2014 -0400 @@ -1185,6 +1185,30 @@ """.format(html.escape(SIMPLE_XMLFILE, True)) +XINCLUDE["Recursive1.xml"] = """\ + + +

The following is the source code of Recursive2.xml:

+ +
+""" + +XINCLUDE["Recursive2.xml"] = """\ + + +

The following is the source code of Recursive2.xml:

+ +
+""" + +XINCLUDE["Recursive3.xml"] = """\ + + +

The following is the source code of Recursive2.xml:

+ +
+""" + # # badly formatted xi:include tags @@ -1306,6 +1330,12 @@ ' \n' '') # C5 + document = self.xinclude_loader("Recursive1.xml") + with self.assertRaises(SyntaxError) as cm: + ElementInclude.include(document,self.xinclude_loader) + self.assertEqual(str(cm.exception),"recursive include detected: loaded Recursive2.xml more than once") + + def test_xinclude_failures(self): from xml.etree import ElementInclude diff -r cb04c94014ea Lib/xml/etree/ElementInclude.py --- a/Lib/xml/etree/ElementInclude.py Thu Jun 26 01:36:47 2014 +0200 +++ b/Lib/xml/etree/ElementInclude.py Thu Jun 26 01:09:24 2014 -0400 @@ -97,8 +97,28 @@ # @throws OSError If the function fails to load a given resource. def include(elem, loader=None): + _include(elem, loader, None) + +## +# Expand XInclude directives. Helper function identical to include, +# Only difference is that the already_included array detects +# recursive includes. +# +# @param elem Root element. +# @param loader Optional resource loader. If omitted, it defaults +# to {@link default_loader}. If given, it should be a callable +# that implements the same interface as default_loader. +# @param already_included includes a list of already included files +# in order (prevention of infinite include condition) +# @throws FatalIncludeError If the function fails to include a given +# resource, or if the tree contains malformed XInclude elements. +# @throws OSError If the function fails to load a given resource. + +def _include(elem, loader=None, already_included=None): if loader is None: loader = default_loader + if already_included == None: + already_included = [] # look for xinclude elements i = 0 while i < len(elem): @@ -114,6 +134,13 @@ "cannot load %r as %r" % (href, parse) ) node = copy.copy(node) + if not href in already_included: + already_included.append(href) + _include(node,loader,already_included) + else: + raise FatalIncludeError( + "recursive include detected: loaded %s more than once" % (href) + ) if e.tail: node.tail = (node.tail or "") + e.tail elem[i] = node