summaryrefslogtreecommitdiffstats
path: root/utils_xml.py
diff options
context:
space:
mode:
authorJan Pokorný <jpokorny@redhat.com>2014-05-28 00:31:50 +0200
committerJan Pokorný <jpokorny@redhat.com>2014-05-28 00:31:50 +0200
commit181244c99c9ca78ece75db86c213a3cf0469d181 (patch)
treea0efb765c43ff7d48359c6a446f3444b2ce31725 /utils_xml.py
parent1429d653fa2434debdf618dcaab734a9555bdb48 (diff)
downloadclufter-181244c99c9ca78ece75db86c213a3cf0469d181.tar.gz
clufter-181244c99c9ca78ece75db86c213a3cf0469d181.tar.xz
clufter-181244c99c9ca78ece75db86c213a3cf0469d181.zip
utils_xml: XML helpers incl. rng_pivot to be used for validation
+ unittest Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
Diffstat (limited to 'utils_xml.py')
-rw-r--r--utils_xml.py57
1 files changed, 57 insertions, 0 deletions
diff --git a/utils_xml.py b/utils_xml.py
new file mode 100644
index 0000000..c10e3bc
--- /dev/null
+++ b/utils_xml.py
@@ -0,0 +1,57 @@
+# -*- coding: UTF-8 -*-
+# Copyright 2014 Red Hat, Inc.
+# Part of clufter project
+# Licensed under GPLv2+ (a copy included | http://gnu.org/licenses/gpl-2.0.txt)
+"""XML helpers"""
+__author__ = "Jan Pokorný <jpokorny @at@ Red Hat .dot. com>"
+
+from copy import deepcopy
+from lxml import etree
+
+from .error import ClufterPlainError
+from .utils import selfaware
+
+
+NAMESPACES = {
+ 'rng': 'http://relaxng.org/ns/structure/1.0'
+}
+
+
+class UtilsXmlError(ClufterPlainError):
+ pass
+
+
+@selfaware
+def rng_pivot(me, et, tag):
+ """Given Relax NG grammar etree as `et`, change start tag (in situ!)"""
+ start = et.xpath("/rng:grammar/rng:start", namespaces=NAMESPACES)
+ if len(start) != 1:
+ raise UtilsXmlError("Cannot change start if grammar's `start' is"
+ " not contained exactly once ({0} times)"
+ .format(len(start)))
+ target = et.xpath("//rng:element[@name = '{0}']".format(tag),
+ namespaces=NAMESPACES)
+ if len(target) != 1:
+ raise UtilsXmlError("Cannot change start if the start element `{0}'"
+ " is not contained exactly once ({1} times)"
+ .format(tag, len(target)))
+ start, target = start[0], target[0]
+ parent_start, parent_target = start.getparent(), target.getparent()
+ index_target = parent_target.index(target)
+ label = me.__name__ + '_' + tag
+
+ # target's content place directly under /grammar wrapped with new define...
+ new_define = etree.Element('define', name=label)
+ new_define.append(target)
+ parent_start.append(new_define)
+
+ # ... while the original occurrence substituted in-situ with the reference
+ new_ref = etree.Element('ref', name=label)
+ parent_target.insert(index_target, new_ref)
+
+ # ... and finally /grammar/start pointed anew to refer to the new label
+ start_ref = deepcopy(new_ref)
+ start.clear()
+ start.append(start_ref)
+
+ return et