Skip to content

Commit 894f06c

Browse files
committed
Merge remote-tracking branch 'origin/xml-improved-2'
2 parents c677f36 + e6e7007 commit 894f06c

File tree

3 files changed

+48
-89
lines changed

3 files changed

+48
-89
lines changed

tests/test_model.py

+24-74
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ def test_xml_config(xml_safe_data_model, xml_safe_data):
736736
# convert InstanceValue to an XML-encoded string
737737
xml_obj = inst.to_xml()
738738
xml_text = ET.tostring(xml_obj).decode("utf-8")
739-
#assert(xml_text == expected_xml_stripped) # fails, see Issue #87
739+
assert(xml_text == expected_xml_stripped)
740740

741741
# convert XML-encoded string back to an InstanceValue
742742
parser = XMLParser(expected_xml_stripped)
@@ -754,7 +754,6 @@ def test_xml_config(xml_safe_data_model, xml_safe_data):
754754

755755

756756

757-
758757
def test_xml_rpc(data_model):
759758
'''
760759
Encodes known "raw data" RPC input & outputs to an XML strings and back again.
@@ -800,7 +799,7 @@ def test_xml_rpc(data_model):
800799

801800
# convert raw object to an InstanceValue
802801
# - an ObjectValue, not a RootNode as per DataModel.from_raw()
803-
input_inst_val = sn_rpc.from_raw(input_obj, allow_nodata=True)
802+
input_inst_val = sn_rpc.from_raw(input_obj)
804803
assert(str(input_inst_val) == str(input_obj))
805804

806805
# convert InstanceValue to an Instance (a RootNode)
@@ -817,7 +816,7 @@ def test_xml_rpc(data_model):
817816
# - an ObjectValue, not a RootNode as per DataModel.from_xml()
818817
parser = XMLParser(input_xml_text)
819818
input_xml_et_obj2 = parser.root
820-
input_inst_val2 = sn_rpc.from_xml(input_xml_et_obj2, isroot=True, allow_nodata=True)
819+
input_inst_val2 = sn_rpc.from_xml(input_xml_et_obj2)
821820
assert(input_inst_val2 == input_inst_val)
822821

823822
# convert InstanceValue back to an Instance (a RootNode)
@@ -837,7 +836,7 @@ def test_xml_rpc(data_model):
837836

838837
# convert raw object to an InstanceValue
839838
# - an ObjectValue, not a RootNode as per DataModel.from_raw()
840-
output_inst_val = sn_rpc.from_raw(output_obj, allow_nodata=True)
839+
output_inst_val = sn_rpc.from_raw(output_obj)
841840
assert(str(output_inst_val) == str(output_obj))
842841

843842
# convert InstanceValue to an Instance (a RootNode)
@@ -854,7 +853,7 @@ def test_xml_rpc(data_model):
854853
# - an ObjectValue, not a RootNode as per DataModel.from_xml()
855854
parser = XMLParser(output_xml_text)
856855
output_xml_et_obj2 = parser.root
857-
output_inst_val2 = sn_rpc.from_xml(output_xml_et_obj2, isroot=True, allow_nodata=True)
856+
output_inst_val2 = sn_rpc.from_xml(output_xml_et_obj2)
858857
assert(output_inst_val2 == output_inst_val)
859858

860859
# convert InstanceValue back to an Instance (a RootNode)
@@ -867,7 +866,6 @@ def test_xml_rpc(data_model):
867866
assert(output_rv2 == output_obj)
868867

869868

870-
871869
def test_xml_action(data_model):
872870
'''
873871
Encodes known "raw data" Action input & outputs to an XML strings and back again.
@@ -887,7 +885,7 @@ def test_xml_action(data_model):
887885

888886
output_xml_stripped = strip_pretty(output_xml_pretty)
889887

890-
# get the schema node for the 'action'
888+
# get the schema node for the 'action'
891889
sn_action = data_model.get_schema_node("/test:contA/listA/contD/acA")
892890
assert(type(sn_action) == RpcActionNode)
893891

@@ -903,7 +901,7 @@ def test_xml_action(data_model):
903901

904902
# convert raw object to an InstanceValue
905903
# - an ObjectValue, not a RootNode as per DataModel.from_raw()
906-
output_inst_val = sn_action.from_raw(output_obj, allow_nodata=True)
904+
output_inst_val = sn_action.from_raw(output_obj)
907905
assert(str(output_inst_val) == str(output_obj))
908906

909907
# convert InstanceValue to an Instance (a RootNode)
@@ -920,7 +918,7 @@ def test_xml_action(data_model):
920918
# - an ObjectValue, not a RootNode as per DataModel.from_xml()
921919
parser = XMLParser(output_xml_text)
922920
output_xml_et_obj2 = parser.root
923-
output_inst_val2 = sn_action.from_xml(output_xml_et_obj2, isroot=True, allow_nodata=True)
921+
output_inst_val2 = sn_action.from_xml(output_xml_et_obj2)
924922
assert(output_inst_val2 == output_inst_val)
925923

926924
# convert InstanceValue back to an Instance (a RootNode)
@@ -946,76 +944,28 @@ def test_xml_notification(data_model):
946944
sn_notif = data_model.get_schema_node("/testb:noA")
947945
assert(type(sn_notif) == NotificationNode)
948946

949-
#######
950-
# NOA #
951-
#######
947+
#########
948+
# NOTIF # (most common?)
949+
#########
952950

953-
noA_obj = {
954-
"testb:leafO" : True
951+
notif_obj = {
952+
"testb:noA" : {
953+
"leafO" : True
954+
}
955955
}
956-
noA_xml_pretty = """
957-
<leafO xmlns="http://example.com/testb">true</leafO>
956+
notif_xml_pretty = """
957+
<noa xmlns="http://example.com/testb">
958+
<leafO>true</leafO>
959+
</noa>
958960
"""
959-
noA_xml_stripped = strip_pretty(noA_xml_pretty)
960-
961-
# convert raw object to an InstanceValue
962-
# - an ObjectValue, not a RootNode as per DataModel.from_raw()
963-
noA_inst_val = sn_notif.from_raw(noA_obj, allow_nodata=True)
964-
assert(str(noA_inst_val) == str(noA_obj))
961+
notif_xml_stripped = strip_pretty(notif_xml_pretty)
965962

966-
# convert InstanceValue to an Instance (a RootNode)
967-
noA_inst = RootNode(noA_inst_val, sn_notif, data_model.schema_data, noA_inst_val.timestamp)
968-
noA_inst.validate(ctype=ContentType.all)
969-
assert(noA_inst.raw_value() == noA_obj)
970963

971-
# convert Instance to an XML-encoded string and compare to known-good
972-
noA_xml_et_obj = noA_inst.to_xml()
973-
noA_xml_text = ET.tostring(noA_xml_et_obj).decode("utf-8")
974-
assert(noA_xml_text == noA_xml_stripped)
964+
# convert raw object to an InstanceValue, an ObjectValue, not a RootNode as per DataModel.from_raw()
965+
notif_inst_val = data_model.schema.from_raw(notif_obj) # , force_namespace=True) #)
975966

976-
# convert noa's XML-encoded string back to an InstanceValue
977-
# - an ObjectValue, not a RootNode as per DataModel.from_xml()
978-
parser = XMLParser(noA_xml_text)
979-
noA_xml_et_obj2 = parser.root
980-
noA_inst_val2 = sn_notif.from_xml(noA_xml_et_obj2, isroot=True, allow_nodata=True)
981-
assert(noA_inst_val2 == noA_inst_val)
967+
assert(str(notif_inst_val) == str(notif_obj))
982968

983-
# convert InstanceValue back to an Instance (a RootNode)
984-
noA_inst2 = RootNode(noA_inst_val2, sn_notif, data_model.schema_data, noA_inst_val2.timestamp)
985-
noA_inst2.validate(ctype=ContentType.all)
986-
assert(noA_inst2.raw_value() == noA_obj)
987-
988-
# convert Instance to raw value and ensure same
989-
noA_rv2 = noA_inst2.raw_value()
990-
assert(noA_rv2 == noA_obj)
991-
992-
993-
994-
995-
# Commenting out since none work
996-
#
997-
# #########
998-
# # NOTIF # (most common?)
999-
# #########
1000-
#
1001-
# notif_obj = {
1002-
# "testb:noA" : {
1003-
# "leafO" : True
1004-
# }
1005-
# }
1006-
# notif_xml_pretty = """
1007-
# <noa xmlns="http://example.com/testb">
1008-
# <leafO>true</leafO>
1009-
# </noa>
1010-
# """
1011-
# notif_xml_stripped = strip_pretty(notif_xml_pretty)
1012-
#
1013-
#
1014-
# # convert raw object to an InstanceValue, an ObjectValue, not a RootNode as per DataModel.from_raw()
1015-
# notif_inst_val = sn_notif.from_raw(notif_obj, allow_nodata=True)
1016-
# assert(str(notif_inst_val) == str(notif_obj))
1017-
#
1018-
#
1019969
# ###################
1020970
# # JSON - RESTCONF # (per RFC 8040)
1021971
# ###################
@@ -1159,7 +1109,7 @@ def test_top_level_nodes(data_model):
11591109
# #print("root = " + str(root))
11601110
#
11611111
# sn = data_model.get_schema_node("/")
1162-
# instval = sn.from_raw(rv, allow_nodata=True)
1112+
# instval = sn.from_raw(rv)
11631113
# #print("instval = " + str(instval))
11641114
#
11651115
# inst = RootNode(instval, sn, data_model.schema_data, instval.timestamp)

yangson/instance.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,13 @@ def to_xml(self: "InstanceNode", filter: OutputFilter = OutputFilter(), elem: ET
552552
# Array outside an Object doesn't make sense
553553
raise NotImplementedError
554554
else:
555-
element.text = self.schema_node.type.to_xml(self.value)
555+
sn = self.schema_node
556+
if isinstance(sn.type, IdentityrefType) and sn.ns != self.value[1]:
557+
module = self.schema_data.modules_by_name.get(self.value[1])
558+
if not module:
559+
raise MissingModuleNamespace(sn.ns)
560+
element.attrib['xmlns:'+self.value[1]] = module.xml_namespace
561+
element.text = sn.type.to_xml(self.value)
556562

557563
if elem is not None:
558564
return element
@@ -1336,3 +1342,5 @@ def _key_predicates(self: "InstanceIdParser") -> EntryKeys:
13361342
ChoiceNode, DataNode, InputNode,
13371343
InternalNode, LeafNode, LeafListNode, ListNode, NotificationNode,
13381344
OutputNode, RpcActionNode, SequenceNode, TerminalNode)
1345+
from .datatype import (
1346+
IdentityrefType)

yangson/schemanode.py

+15-14
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ def data_children(self: "InternalNode") -> List["DataNode"]:
454454
res.extend(child.data_children())
455455
return res
456456

457-
def from_raw(self: "InternalNode", rval: RawObject, jptr: JSONPointer = "", allow_nodata: bool = False) -> ObjectValue:
457+
def from_raw(self: "InternalNode", rval: RawObject, jptr: JSONPointer = "") -> ObjectValue:
458458
"""Override the superclass method."""
459459
if not isinstance(rval, dict):
460460
raise RawTypeError(jptr, "object")
@@ -469,33 +469,33 @@ def from_raw(self: "InternalNode", rval: RawObject, jptr: JSONPointer = "", allo
469469
res[qn] = self._process_metadata(rval[qn], jptr)
470470
else:
471471
cn = self._iname2qname(qn)
472-
if allow_nodata:
472+
ch = self.get_data_child(*cn)
473+
if jptr == "" and ch is None:
473474
ch = self.get_child(*cn)
474-
else:
475-
ch = self.get_data_child(*cn)
475+
if not isinstance(ch, SchemaTreeNode):
476+
ch = None
476477
npath = jptr + "/" + qn
477478
if ch is None:
478479
raise RawMemberError(npath)
479-
if (allow_nodata or isinstance(self, SchemaTreeNode) or
480-
self.ns != ch.ns):
480+
if jptr == "" or self.ns != ch.ns:
481481
iname = '{1}:{0}'.format(*ch.qual_name)
482482
else:
483483
iname = ch.name
484484
res[iname] = ch.from_raw(rval[qn], npath)
485485
return res
486486

487-
def from_xml(self: "InternalNode", rval: ET.Element, jptr: JSONPointer = "", isroot: bool = False, allow_nodata: bool = False) -> ObjectValue:
487+
def from_xml(self: "InternalNode", rval: ET.Element, jptr: JSONPointer = "") -> ObjectValue:
488488
res = ObjectValue()
489-
if isroot:
490-
self._process_xmlobj_child(res, None, rval, jptr, allow_nodata)
489+
if isinstance(self, RpcActionNode) and jptr == "":
490+
self._process_xmlobj_child(res, None, rval, jptr)
491491
else:
492492
for xmlchild in rval:
493-
self._process_xmlobj_child(res, rval, xmlchild, jptr, allow_nodata)
493+
self._process_xmlobj_child(res, rval, xmlchild, jptr)
494494
return res
495495

496496
def _process_xmlobj_child(
497497
self: "InternalNode", res: ObjectValue, rval: ET.Element,
498-
xmlchild: ET.Element, jptr: JSONPointer, allow_nodata):
498+
xmlchild: ET.Element, jptr: JSONPointer):
499499
if xmlchild.tag[0] == '{':
500500
xmlns, name = xmlchild.tag[1:].split('}')
501501
nsmap = self.schema_root().schema_data.modules_by_ns
@@ -509,10 +509,11 @@ def _process_xmlobj_child(
509509
fqn = ns + ':' + name
510510
qn = fqn if ns != self.ns else name
511511

512-
if allow_nodata:
512+
ch = self.get_data_child(name, ns)
513+
if jptr == "" and ch is None:
513514
ch = self.get_child(name, ns)
514-
else:
515-
ch = self.get_data_child(name, ns)
515+
if not isinstance(ch, SchemaTreeNode):
516+
ch = None
516517
npath = jptr + "/" + qn
517518
if ch is None:
518519
raise RawMemberError(npath)

0 commit comments

Comments
 (0)