diff -r fd9f7bdd7472 Lib/test/test_xml_etree.py
--- a/Lib/test/test_xml_etree.py Fri Jun 20 01:38:37 2014 -0700
+++ b/Lib/test/test_xml_etree.py Sun Jun 22 14:02:28 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 fd9f7bdd7472 Lib/xml/etree/ElementInclude.py
--- a/Lib/xml/etree/ElementInclude.py Fri Jun 20 01:38:37 2014 -0700
+++ b/Lib/xml/etree/ElementInclude.py Sun Jun 22 14:02:28 2014 -0400
@@ -114,6 +114,7 @@
"cannot load %r as %r" % (href, parse)
)
node = copy.copy(node)
+ _include(node,loader,[href])
if e.tail:
node.tail = (node.tail or "") + e.tail
elem[i] = node
@@ -141,3 +142,73 @@
else:
include(e, loader)
i = i + 1
+
+##
+# 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):
+ e = elem[i]
+ if e.tag == XINCLUDE_INCLUDE:
+ # process xinclude directive
+ href = e.get("href")
+ parse = e.get("parse", "xml")
+ if parse == "xml":
+ node = loader(href, parse)
+ if node is None:
+ raise FatalIncludeError(
+ "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) ### newly added code here
+ 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
+ elif parse == "text":
+ text = loader(href, parse, e.get("encoding"))
+ if text is None:
+ raise FatalIncludeError(
+ "cannot load %r as %r" % (href, parse)
+ )
+ if i:
+ node = elem[i-1]
+ node.tail = (node.tail or "") + text + (e.tail or "")
+ else:
+ elem.text = (elem.text or "") + text + (e.tail or "")
+ del elem[i]
+ continue
+ else:
+ raise FatalIncludeError(
+ "unknown parse type in xi:include tag (%r)" % parse
+ )
+ elif e.tag == XINCLUDE_FALLBACK:
+ raise FatalIncludeError(
+ "xi:fallback tag must be child of xi:include (%r)" % e.tag
+ )
+ else:
+ include(e, loader)
+ i = i + 1