Skip to content

Commit

Permalink
Unify wildcard/anyType node parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
tefra committed Feb 7, 2021
1 parent 782546c commit 4c7405d
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repos:
- id: pyupgrade
args: [--py37-plus]
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.3.6
rev: v2.4.0
hooks:
- id: reorder-python-imports
- repo: https://github.com/ambv/black
Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/defxmlschema/chapter12.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"other_attributes": {
"{http://example.org/oth}custom": "12"
}
}
},
"substituted": false
}
]
}
3 changes: 2 additions & 1 deletion tests/fixtures/defxmlschema/chapter17.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"quantity": 1,
"color": null,
"number": 563
}
},
"substituted": false
}
]
},
Expand Down
2 changes: 1 addition & 1 deletion tests/formats/dataclass/parsers/test_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_end(self, mock_emit_event):
objects = []
queue = []
var = XmlVar(text=True, name="foo", qname="foo", types=[bool])
queue.append(PrimitiveNode(var=var, ns_map={}))
queue.append(PrimitiveNode.from_var(var, {}))

result = self.parser.end(queue, objects, "enabled", "true", None)
self.assertTrue(result)
Expand Down
2 changes: 1 addition & 1 deletion tests/formats/dataclass/serializers/test_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def test_write_any_type_with_derived_element_primitive(self):

def test_write_any_type_with_derived_element_dataclass(self):
var = XmlVar(wildcard=True, qname="a", name="a")
value = DerivedElement(qname="a", value=BookForm(title="def"))
value = DerivedElement(qname="a", value=BookForm(title="def"), substituted=True)
expected = [
(XmlWriterEvent.START, "a"),
(XmlWriterEvent.ATTR, "lang", "en"),
Expand Down
1 change: 1 addition & 0 deletions xsdata/formats/dataclass/models/generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ class DerivedElement(Generic[T]):

qname: str
value: T
substituted: bool = False
37 changes: 25 additions & 12 deletions xsdata/formats/dataclass/parsers/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class ElementNode(XmlNode):
position: int
mixed: bool = False
derived: bool = False
substituted: bool = False
assigned: Set = field(default_factory=set)

def bind(self, qname: str, text: NoneStr, tail: NoneStr, objects: List) -> bool:
Expand All @@ -80,7 +81,7 @@ def bind(self, qname: str, text: NoneStr, tail: NoneStr, objects: List) -> bool:

obj = self.meta.clazz(**params)
if self.derived:
obj = DerivedElement(qname=qname, value=obj)
obj = DerivedElement(qname=qname, value=obj, substituted=self.substituted)

objects.append((qname, obj))

Expand Down Expand Up @@ -119,27 +120,38 @@ def build_node(
position=position,
)

xsi_type = ParserUtils.xsi_type(attrs, ns_map)

if var.clazz:
return self.build_element_node(
var.clazz, attrs, ns_map, position, var.derived
var.clazz,
attrs,
ns_map,
position,
var.derived,
xsi_type,
)

if not var.any_type and not var.wildcard:
return PrimitiveNode.from_var(var, ns_map)

xsi_type = ParserUtils.xsi_type(attrs, ns_map)
datatype = DataType.from_qname(xsi_type) if xsi_type else None
derived = var.derived or var.wildcard
clazz = None

if xsi_type and not datatype:
clazz = self.context.find_type(xsi_type)

if datatype:
return PrimitiveNode.from_datatype(datatype, derived, ns_map)

node = None
clazz = None
if xsi_type:
clazz = self.context.find_type(xsi_type)

if clazz:
return self.build_element_node(clazz, attrs, ns_map, position, derived)
node = self.build_element_node(
clazz, attrs, ns_map, position, derived, xsi_type
)

if node:
return node

return WildcardNode(var=var, attrs=attrs, ns_map=ns_map, position=position)

Expand All @@ -166,12 +178,12 @@ def build_element_node(
ns_map: Dict,
position: int,
derived: bool,
xsi_type: Optional[str] = None,
) -> Optional[XmlNode]:
xsi_type = ParserUtils.xsi_type(attrs, ns_map)
is_nillable = ParserUtils.is_nillable(attrs)

meta = self.context.fetch(clazz, self.meta.namespace, xsi_type)

if not is_nillable and meta.nillable:
if not meta or (meta.nillable and not ParserUtils.is_nillable(attrs)):
return None

return ElementNode(
Expand All @@ -182,6 +194,7 @@ def build_element_node(
context=self.context,
position=position,
derived=derived,
substituted=xsi_type is not None,
mixed=self.meta.has_var(mode=FindMode.MIXED_CONTENT),
)

Expand Down
2 changes: 1 addition & 1 deletion xsdata/formats/dataclass/serializers/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def write_derived_element(
):
if is_dataclass(value.value):
xsi_type = None
if not var.mixed:
if value.substituted:
meta = self.context.build(value.value.__class__)
xsi_type = QName(meta.source_qname)

Expand Down

0 comments on commit 4c7405d

Please sign in to comment.