diff --git a/pyxform/aliases.py b/pyxform/aliases.py
index c428b44dc..c388ef19f 100644
--- a/pyxform/aliases.py
+++ b/pyxform/aliases.py
@@ -85,6 +85,7 @@
u"no_app_error_string" : u"bind::jr:noAppErrorString",
u"requiredMsg" : u"bind::jr:requiredMsg",
u"required_message" : u"bind::jr:requiredMsg",
+ u"body":u"control"
}
list_header = {
u"caption": constants.LABEL,
diff --git a/pyxform/question.py b/pyxform/question.py
index 68eb09072..5fa941d87 100644
--- a/pyxform/question.py
+++ b/pyxform/question.py
@@ -17,11 +17,19 @@ def validate(self):
)
def xml_instance(self):
+ survey = self.get_root()
+ attributes = {}
+ attributes.update(self.get(u'instance', {}))
+ for key, value in attributes.items():
+ attributes[key] = survey.insert_xpaths(value)
if self.get(u"default"):
#survey = self.get_root()
#return node(self.name, survey.insert_xpaths(unicode(self.get(u"default"))))
- return node(self.name, unicode(self.get(u"default")))
- return node(self.name)
+ return node(self.name,
+ unicode(self.get(u"default")),
+ **attributes
+ )
+ return node(self.name, **attributes)
def xml_control(self):
return None
@@ -35,14 +43,12 @@ class InputQuestion(Question):
def xml_control(self):
control_dict = self.control
label_and_hint = self.xml_label_and_hint()
- control_dict['ref'] = self.get_xpath()
-
- # for SurveyCTO's support for external intents, resolve field references in appearance column:
survey = self.get_root()
- appearance=control_dict.get('appearance')
- if appearance is not None:
- control_dict['appearance'] = survey.insert_xpaths(appearance)
-
+ # Resolve field references in attributes
+ for key, value in control_dict.items():
+ control_dict[key] = survey.insert_xpaths(value)
+ control_dict['ref'] = self.get_xpath()
+
result = node(**control_dict)
if label_and_hint:
for element in self.xml_label_and_hint():
@@ -63,18 +69,16 @@ class TriggerQuestion(Question):
def xml_control(self):
control_dict = self.control
- if u"appearance" in control_dict:
- return node(
- u"trigger", ref=self.get_xpath(),
- appearance=control_dict[u"appearance"],
- *self.xml_label_and_hint()
- )
- else:
- return node(u"trigger",
- ref=self.get_xpath(),
- *self.xml_label_and_hint()
- )
-
+ survey = self.get_root()
+ # Resolve field references in attributes
+ for key, value in control_dict.items():
+ control_dict[key] = survey.insert_xpaths(value)
+ control_dict['ref'] = self.get_xpath()
+ return node(
+ u"trigger",
+ *self.xml_label_and_hint(),
+ **control_dict
+ )
class UploadQuestion(Question):
def _get_media_type(self):
@@ -82,22 +86,13 @@ def _get_media_type(self):
def xml_control(self):
control_dict = self.control
- if u"appearance" in control_dict:
- return node(
- u"upload",
- ref=self.get_xpath(),
- mediatype=self._get_media_type(),
- appearance=control_dict[u"appearance"],
- *self.xml_label_and_hint()
- )
- else:
- return node(
- u"upload",
- ref=self.get_xpath(),
- mediatype=self._get_media_type(),
- *self.xml_label_and_hint()
- )
-
+ control_dict['ref'] = self.get_xpath()
+ control_dict['mediatype'] = self._get_media_type()
+ return node(
+ u"upload",
+ *self.xml_label_and_hint(),
+ **control_dict
+ )
class Option(SurveyElement):
@@ -162,20 +157,16 @@ def validate(self):
def xml_control(self):
assert self.bind[u"type"] in [u"select", u"select1"]
-
survey = self.get_root()
control_dict = self.control.copy()
+ # Resolve field references in attributes
+ for key, value in control_dict.items():
+ control_dict[key] = survey.insert_xpaths(value)
control_dict['ref'] = self.get_xpath()
- # for SurveyCTO's dynamic-select support, resolve field references in appearance column:
- appearance = control_dict.get('appearance')
- if appearance is not None:
- control_dict['appearance'] = survey.insert_xpaths(appearance)
-
result = node(**control_dict)
for element in self.xml_label_and_hint():
result.appendChild(element)
- survey = self.get_root()
# itemset are only supposed to be strings, check to prevent the rare dicts that show up
if self['itemset'] and isinstance( self['itemset'] , basestring):
choice_filter = self.get('choice_filter')
diff --git a/pyxform/section.py b/pyxform/section.py
index fc8ece39d..7927c5eed 100644
--- a/pyxform/section.py
+++ b/pyxform/section.py
@@ -25,7 +25,14 @@ def xml_instance(self, **kwargs):
"""
Creates an xml representation of the section
"""
- result = node(self.name, **kwargs)
+ attributes = {}
+ attributes.update(kwargs)
+ attributes.update(self.get(u'instance', {}))
+ survey = self.get_root()
+ # Resolve field references in attributes
+ for key, value in attributes.items():
+ attributes[key] = survey.insert_xpaths(value)
+ result = node(self.name, **attributes)
for child in self.children:
if child.get(u"flat"):
for grandchild in child.xml_instance_array():
@@ -70,10 +77,10 @@ def xml_control(self):
"""
control_dict = self.control.copy()
- jrcount = control_dict.get('jr:count')
- if jrcount:
- survey = self.get_root()
- control_dict['jr:count'] = survey.insert_xpaths(jrcount)
+ survey = self.get_root()
+ # Resolve field references in attributes
+ for key, value in control_dict.items():
+ control_dict[key] = survey.insert_xpaths(value)
repeat_node = node(u"repeat", nodeset=self.get_xpath(), **control_dict)
for n in Section.xml_control(self):
@@ -85,7 +92,7 @@ def xml_control(self):
u"group", self.xml_label(), repeat_node,
ref=self.get_xpath()
)
- return node(u"group", repeat_node, ref=self.get_xpath())
+ return node(u"group", repeat_node, ref=self.get_xpath(), **self.control)
#I'm anal about matching function signatures when overriding a function, but there's no reason for kwargs to be an argument
def xml_instance(self, **kwargs):
@@ -111,10 +118,17 @@ def xml_control(self):
return None
children = []
- attrs = {}
+ attributes = {}
+ attributes.update(self.control)
+
+ survey = self.get_root()
+
+ # Resolve field references in attributes
+ for key, value in attributes.items():
+ attributes[key] = survey.insert_xpaths(value)
if not self.get('flat'):
- attrs['ref'] = self.get_xpath()
+ attributes['ref'] = self.get_xpath()
if 'label' in self and len(self['label']) > 0:
children.append(self.xml_label())
@@ -122,13 +136,13 @@ def xml_control(self):
children.append(n)
if u"appearance" in control_dict:
- attrs['appearance'] = control_dict['appearance']
+ attributes['appearance'] = control_dict['appearance']
if u"intent" in control_dict:
survey = self.get_root()
- attrs['intent'] = survey.insert_xpaths(control_dict['intent'])
+ attributes['intent'] = survey.insert_xpaths(control_dict['intent'])
- return node(u"group", *children, **attrs)
+ return node(u"group", *children, **attributes)
def to_json_dict(self):
# This is quite hacky, might want to think about a smart way
diff --git a/pyxform/survey_element.py b/pyxform/survey_element.py
index a5425b908..c57fcea2d 100644
--- a/pyxform/survey_element.py
+++ b/pyxform/survey_element.py
@@ -34,6 +34,7 @@ class SurveyElement(dict):
u"intent": unicode,
u"jr:count" : unicode,
u"bind": dict,
+ u"instance": dict,
u"control": dict,
u"media": dict,
# this node will also have a parent and children, like a tree!
diff --git a/pyxform/tests/attribute_columns_test.py b/pyxform/tests/attribute_columns_test.py
new file mode 100644
index 000000000..aef9d3d04
--- /dev/null
+++ b/pyxform/tests/attribute_columns_test.py
@@ -0,0 +1,47 @@
+"""
+Some tests for the new (v0.9) spec is properly implemented.
+"""
+import unittest2 as unittest
+import codecs
+import os
+import sys
+# Hack to make sure that pyxform is on the python import path
+parentdir = os.path.dirname(os.path.dirname(
+ os.path.dirname(os.path.abspath(__file__))))
+sys.path.insert(0, parentdir)
+import pyxform
+from pyxform.errors import PyXFormError
+
+DIR = os.path.dirname(__file__)
+
+
+class attribute_columns_test(unittest.TestCase):
+
+ maxDiff = None
+
+ def runTest(self):
+ filename = "attribute_columns_test.xlsx"
+ path_to_excel_file = os.path.join(DIR, "example_xls", filename)
+ # Get the xform output path:
+ root_filename, ext = os.path.splitext(filename)
+ output_path = os.path.join(DIR, "test_output", root_filename + ".xml")
+ expected_output_path = os.path.join(DIR, "test_expected_output",
+ root_filename + ".xml")
+ # Do the conversion:
+ warnings = []
+ json_survey = pyxform.xls2json.parse_file_to_json(
+ path_to_excel_file, warnings=warnings)
+ survey = pyxform.create_survey_element_from_dict(json_survey)
+ survey.print_xform_to_file(output_path, warnings=warnings)
+ # print warnings
+ # Compare with the expected output:
+ with codecs.open(expected_output_path, 'rb', encoding="utf-8") \
+ as expected_file:
+ with codecs.open(output_path, 'rb', encoding="utf-8") \
+ as actual_file:
+ self.assertMultiLineEqual(
+ expected_file.read(), actual_file.read())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/pyxform/tests/example_xls/attribute_columns_test.xlsx b/pyxform/tests/example_xls/attribute_columns_test.xlsx
new file mode 100644
index 000000000..09b9d9f20
Binary files /dev/null and b/pyxform/tests/example_xls/attribute_columns_test.xlsx differ
diff --git a/pyxform/tests/test_expected_output/attribute_columns_test.xml b/pyxform/tests/test_expected_output/attribute_columns_test.xml
new file mode 100644
index 000000000..f477fd800
--- /dev/null
+++ b/pyxform/tests/test_expected_output/attribute_columns_test.xml
@@ -0,0 +1,959 @@
+
+
+
+ Spec test
+
+
+
+
+
+ -
+
+
+ jr://images/a.jpg
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Yes
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Yes
+
+
+ -
+
+
+ jr://images/img_test.jpg
+ jr://audio/audio_test.wav
+ jr://video/test.mov
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ jr://images/a.jpg
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ The goal of this test is to try out all the different media types in many languages to see if there are any bugs inserting media.
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/b.jpg
+
+
+ Yes
+
+
+ No
+
+
+ -
+
+
+ Yes
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ -
+
+
+ Yes
+
+
+ Yes
+
+
+ jr://images/b.jpg
+
+
+ Yes
+
+
+ No
+
+
+ -
+
+
+ a note
+
+
+ Yes
+
+
+ No
+
+
+ jr://images/img_test.jpg
+
+
+ No
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ ni hao
+
+
+ 是
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ 是
+
+
+ -
+
+
+ jr://images/-
+ jr://audio/chinese_audio.wav
+ jr://video/-
+ 您好
+
+
+ -
+
+
+ -
+
+
+ 没有
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ ni hao
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ 是
+
+
+ 没有
+
+
+ 没有
+
+
+ 是
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ 對不起 ,你可以不選擇“是”和“否”。
+
+
+ -
+
+
+ -
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ 您好
+
+
+ -
+
+
+ 是
+
+
+ 是
+
+
+ jr://images/-
+
+
+ 是
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ 是
+
+
+ 没有
+
+
+ -
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ video_test
+
+
+ 1
+
+
+ table list question
+
+
+ autocomplete_chars_test
+
+
+ constrained decimal
+
+
+ -
+
+
+ This launches a fictional application to get an integer result.
+
+
+ repeat_test
+
+
+ select multiple test
+
+
+ -
+
+
+ deviceid_test_output:
+
+ numerical name test
+
+
+ compact-test
+
+
+ start test output:
+
+ -
+
+
+ label-test
+
+
+ jr://images/img_test_2.jpg
+ jr://audio/-
+ jr://video/-
+ text_image_audio_video_test
+
+
+ deviceid_test_output:
+
+ date_test
+
+
+ -
+
+
+ jr://images/-
+
+
+ autocomplete_test
+
+
+ phonenumber_test_output:
+
+ -
+
+
+ -
+
+
+ image_test
+
+
+ datetime_test
+
+
+ jr://images/-
+
+
+ today_test_output:
+
+ -
+
+
+ audio_test
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ a integer
+
+
+
+
+
+ jr://images/-
+
+
+ labeled select group test
+
+
+ geopoint_test
+
+
+ Sorry , you can't select yes and no.
+
+
+ Skip to end
+
+
+ -
+
+
+ Your name is
+
+ time_test
+
+
+ -
+
+
+ simserial_test_output:
+
+ note_test
+
+
+ Enter your name
+
+
+ Enter an address
+
+
+ end test output:
+
+ acknowledge_test
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ You entered an email address
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ required_text
+
+
+ list-nolabel-test
+
+
+ boolean name test
+
+
+ compact-2-test
+
+
+ barcode_test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_1/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+
+
+
+ Try replacing my_name with a invalid variable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+ hint
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+ -
+
+ a
+
+ -
+
+ b
+
+
+
+
+ -
+
+ a
+
+ -
+
+ b
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GPS coordinates can only be collected when outside.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pyxform/tests/test_output/attribute_columns_test.xml b/pyxform/tests/test_output/attribute_columns_test.xml
new file mode 100644
index 000000000..f477fd800
--- /dev/null
+++ b/pyxform/tests/test_output/attribute_columns_test.xml
@@ -0,0 +1,959 @@
+
+
+
+ Spec test
+
+
+
+
+
+ -
+
+
+ jr://images/a.jpg
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Yes
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Yes
+
+
+ -
+
+
+ jr://images/img_test.jpg
+ jr://audio/audio_test.wav
+ jr://video/test.mov
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ jr://images/a.jpg
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ The goal of this test is to try out all the different media types in many languages to see if there are any bugs inserting media.
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/b.jpg
+
+
+ Yes
+
+
+ No
+
+
+ -
+
+
+ Yes
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ No
+
+
+ -
+
+
+ Yes
+
+
+ Yes
+
+
+ jr://images/b.jpg
+
+
+ Yes
+
+
+ No
+
+
+ -
+
+
+ a note
+
+
+ Yes
+
+
+ No
+
+
+ jr://images/img_test.jpg
+
+
+ No
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ ni hao
+
+
+ 是
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ 是
+
+
+ -
+
+
+ jr://images/-
+ jr://audio/chinese_audio.wav
+ jr://video/-
+ 您好
+
+
+ -
+
+
+ -
+
+
+ 没有
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ ni hao
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ 是
+
+
+ 没有
+
+
+ 没有
+
+
+ 是
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ 對不起 ,你可以不選擇“是”和“否”。
+
+
+ -
+
+
+ -
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ 您好
+
+
+ -
+
+
+ 是
+
+
+ 是
+
+
+ jr://images/-
+
+
+ 是
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ 是
+
+
+ 没有
+
+
+ -
+
+
+ 没有
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ video_test
+
+
+ 1
+
+
+ table list question
+
+
+ autocomplete_chars_test
+
+
+ constrained decimal
+
+
+ -
+
+
+ This launches a fictional application to get an integer result.
+
+
+ repeat_test
+
+
+ select multiple test
+
+
+ -
+
+
+ deviceid_test_output:
+
+ numerical name test
+
+
+ compact-test
+
+
+ start test output:
+
+ -
+
+
+ label-test
+
+
+ jr://images/img_test_2.jpg
+ jr://audio/-
+ jr://video/-
+ text_image_audio_video_test
+
+
+ deviceid_test_output:
+
+ date_test
+
+
+ -
+
+
+ jr://images/-
+
+
+ autocomplete_test
+
+
+ phonenumber_test_output:
+
+ -
+
+
+ -
+
+
+ image_test
+
+
+ datetime_test
+
+
+ jr://images/-
+
+
+ today_test_output:
+
+ -
+
+
+ audio_test
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ a integer
+
+
+
+
+
+ jr://images/-
+
+
+ labeled select group test
+
+
+ geopoint_test
+
+
+ Sorry , you can't select yes and no.
+
+
+ Skip to end
+
+
+ -
+
+
+ Your name is
+
+ time_test
+
+
+ -
+
+
+ simserial_test_output:
+
+ note_test
+
+
+ Enter your name
+
+
+ Enter an address
+
+
+ end test output:
+
+ acknowledge_test
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ jr://images/-
+
+
+ -
+
+
+ -
+
+
+ You entered an email address
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ required_text
+
+
+ list-nolabel-test
+
+
+ boolean name test
+
+
+ compact-2-test
+
+
+ barcode_test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_1/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+
+
+
+ Try replacing my_name with a invalid variable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+ hint
+ -
+
+ yes
+
+ -
+
+ no
+
+
+
+
+
+ -
+
+ a
+
+ -
+
+ b
+
+
+
+
+ -
+
+ a
+
+ -
+
+ b
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GPS coordinates can only be collected when outside.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pyxform/utils.py b/pyxform/utils.py
index 327aa875d..e1fd0e8be 100644
--- a/pyxform/utils.py
+++ b/pyxform/utils.py
@@ -23,19 +23,24 @@ def is_valid_xml_tag(tag):
"""
return re.search(r"^" + XFORM_TAG_REGEXP + r"$", tag)
-def node(tag, *args, **kwargs):
+def node(*args, **kwargs):
"""
- tag -- a XML tag
- args -- an array of children to append to the newly created node
+ args[0] -- a XML tag
+ args[1:] -- an array of children to append to the newly created node
or if a unicode arg is supplied it will be used to make a text node
+ kwargs -- attributes
returns a xml.dom.minidom.Element
"""
+ blocked_attributes = ['tag']
+ tag = args[0] if len(args) > 0 else kwargs['tag']
+ args = args[1:]
result = Element(tag)
unicode_args = [u for u in args if type(u) == unicode]
assert len(unicode_args) <= 1
parsedString = False
#kwargs is an xml attribute dictionary, here we convert it to a xml.dom.minidom.Element
for k, v in kwargs.iteritems():
+ if k in blocked_attributes: continue
if k == 'toParseString':
if v == True and len(unicode_args) == 1:
parsedString = True