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