Skip to content

Commit

Permalink
WIP namespace unflattening
Browse files Browse the repository at this point in the history
  • Loading branch information
Bjwebb committed Aug 7, 2024
1 parent 537d72e commit b318322
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 18 deletions.
1 change: 1 addition & 0 deletions examples/iati_namespaces/cmd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$ flatten-tool unflatten --xml --id-name iati-identifier --root-list-path iati-activity --xml-schema examples/iati/iati-activities-schema.xsd examples/iati/iati-common.xsd -f csv examples/iati_namespaces
60 changes: 60 additions & 0 deletions examples/iati_namespaces/expected.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version='1.0' encoding='utf-8'?>
<iati-activities xmlns:customns="http://example.com/2">
<!--XML generated by flatten-tool-->
<iati-activity xmlns:customns="http://example.com/1" last-updated-datetime="2011-10-01T00:00:00+00:00">
<iati-identifier>AA-AAA-123456789-ABC123</iati-identifier>
<reporting-org ref="AA-AAA-123456789" type="40">
<narrative>Organisation name</narrative>
</reporting-org>
<title>
<narrative>A title</narrative>
</title>
<description>
<narrative>A description</narrative>
</description>
<participating-org ref="AA-AAA-123456789" role="1"/>
<activity-status code="2"/>
<activity-date iso-date="2011-10-01" type="1"/>
<recipient-country code="AF" percentage="40"/>
<recipient-country code="XK" percentage="60"/>
<transaction>
<transaction-type code="2"/>
<transaction-date iso-date="2012-01-01"/>
<value value-date="2012-01-01">10</value>
</transaction>
<transaction>
<transaction-type code="3"/>
<transaction-date iso-date="2012-03-03"/>
<value value-date="2012-03-03">20</value>
</transaction>
<customns:test>one</customns:test>
</iati-activity>
<iati-activity last-updated-datetime="2016-01-01T00:00:00+00:00">
<iati-identifier>AA-AAA-123456789-ABC124</iati-identifier>
<reporting-org ref="AA-AAA-123456789" type="40">
<narrative>Organisation name</narrative>
</reporting-org>
<title>
<narrative>Another title</narrative>
</title>
<description>
<narrative>Another description</narrative>
</description>
<participating-org ref="AA-AAA-123456789" role="1"/>
<activity-status code="3"/>
<activity-date iso-date="2016-01-01" type="2"/>
<recipient-country code="AG" percentage="30"/>
<recipient-country code="XK" percentage="70"/>
<transaction>
<transaction-type code="2"/>
<transaction-date iso-date="2013-04-04"/>
<value value-date="2013-04-04">30</value>
</transaction>
<transaction>
<transaction-type code="3"/>
<transaction-date iso-date="2013-05-05"/>
<value value-date="2013-05-05">40</value>
</transaction>
<customns:test>two</customns:test>
</iati-activity>
</iati-activities>
1 change: 1 addition & 0 deletions examples/iati_namespaces/iati-activities-schema.xsd
1 change: 1 addition & 0 deletions examples/iati_namespaces/iati-common.xsd
1 change: 1 addition & 0 deletions examples/iati_namespaces/iati-organisations-schema.xsd
3 changes: 3 additions & 0 deletions examples/iati_namespaces/main.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
iati-identifier,reporting-org/@ref,reporting-org/@type,reporting-org/narrative,participating-org/@role,participating-org/@ref,activity-status/@code,activity-date/@type,activity-date/@iso-date,recipient-country/0/@code,recipient-country/0/@percentage,recipient-country/1/@code,recipient-country/1/@percentage,title/narrative,description/narrative,@last-updated-datetime,@xmlns:customns,customns:test
AA-AAA-123456789-ABC123,AA-AAA-123456789,40,Organisation name,1,AA-AAA-123456789,2,1,2011-10-01,AF,40,XK,60,A title,A description,2011-10-01T00:00:00+00:00,http://example.com/1,one
AA-AAA-123456789-ABC124,AA-AAA-123456789,40,Organisation name,1,AA-AAA-123456789,3,2,2016-01-01,AG,30,XK,70,Another title,Another description,2016-01-01T00:00:00+00:00,http://example.com/2,two
5 changes: 5 additions & 0 deletions examples/iati_namespaces/transactions.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
iati-identifier,transaction/0/transaction-type/@code,transaction/0/transaction-date/@iso-date,transaction/0/value/@value-date,transaction/0/value
AA-AAA-123456789-ABC123,2,2012-01-01,2012-01-01,10
AA-AAA-123456789-ABC123,3,2012-03-03,2012-03-03,20
AA-AAA-123456789-ABC124,2,2013-04-04,2013-04-04,30
AA-AAA-123456789-ABC124,3,2013-05-05,2013-05-05,40
2 changes: 1 addition & 1 deletion flattentool/tests/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _test_example_in_doc_worker(root, filename):


def test_expected_number_of_examples_in_docs_data():
expected = 67
expected = 68
# See _get_examples_in_docs_data()
if sys.version_info[:2] != (3, 8):
expected -= 3
Expand Down
54 changes: 37 additions & 17 deletions flattentool/xml_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ def sort_attributes(data):
return OrderedDict(sorted(attribs) + other)


def child_to_xml(parent_el, tagname, child, toplevel=False, nsmap=None):
def child_to_xml(child_elements, attrib, tagname, child, toplevel=False, nsmap=None):
if hasattr(child, "items"):
child_el = dict_to_xml(child, tagname, toplevel=False, nsmap=nsmap)
if child_el is not None:
parent_el.append(child_el)
child_elements.append(child_el)
else:
if tagname.startswith("@"):
if USING_LXML and toplevel and tagname.startswith("@xmlns"):
nsmap[tagname[1:].split(":", 1)[1]] = str(child)
if USING_LXML and tagname.startswith("@xmlns"):
nsname = tagname[1:].split(":", 1)[1]
nsmap[nsname] = str(child)
return
try:
attr_name = tagname[1:]
Expand All @@ -54,41 +55,60 @@ def child_to_xml(parent_el, tagname, child, toplevel=False, nsmap=None):
+ "}"
+ attr_name.split(":", 1)[1]
)
parent_el.attrib[attr_name] = str(child)
attrib[attr_name] = str(child)
except ValueError as e:
warn(str(e), DataErrorWarning)
elif tagname == "text()":
parent_el.text = str(child)
return str(child)
else:
raise FlattenToolError("Everything should end with text() or an attribute!")
return None


def dict_to_xml(data, tagname, toplevel=True, nsmap=None):
if USING_LXML and ":" in tagname and not toplevel:
if USING_LXML and ":" in tagname and not tagname.startswith("@xmlns"):
tagname = (
"{"
+ nsmap.get(tagname.split(":", 1)[0], "")
+ "}"
+ tagname.split(":", 1)[1]
)
try:
if USING_LXML:
el = ET.Element(tagname, nsmap=nsmap)
else:
el = ET.Element(tagname)
except ValueError as e:
warn(str(e), DataErrorWarning)
return

if USING_LXML:
data = sort_attributes(data)

# We must do this in this order in order to...
child_elements = []
attrib = {}
text = None

for k, v in data.items():
if type(v) == list:
for item in v:
child_to_xml(el, k, item, nsmap=nsmap)
t = child_to_xml(child_elements, attrib, k, item, nsmap=nsmap)
if t:
text = t
else:
t = child_to_xml(
child_elements, attrib, k, v, toplevel=toplevel, nsmap=nsmap
)
if t:
text = t

try:
if USING_LXML:
el = ET.Element(tagname, attrib=attrib, nsmap=nsmap)
else:
child_to_xml(el, k, v, toplevel=toplevel, nsmap=nsmap)
el = ET.Element(tagname, attrib=attrib)
except ValueError as e:
warn(str(e), DataErrorWarning)
return

for child_el in child_elements:
el.append(child_el)
if text:
el.text = text

return el


Expand Down

0 comments on commit b318322

Please sign in to comment.