Commit 00f7916d authored by Katia Saurfelt's avatar Katia Saurfelt
Browse files

feat: add DataObjectGroup on all [Binary|Physical]DataObject descendents of DataObjectPackage.

Use <rng:zeroOrMore/rng:choice> grouping all [Binary|Physical]DataObjects to avoid the problem
if [Binary|Physical]DataObject order (closes #35)

--HG--
branch : seda21
parent 3f22e0b6b094
Pipeline #95377 failed with stages
in 1 minute and 11 seconds
...@@ -447,7 +447,7 @@ class SEDA2ExportAdapter(EntityAdapter): ...@@ -447,7 +447,7 @@ class SEDA2ExportAdapter(EntityAdapter):
class SEDA2RelaxNGExport(RNGMixin, SEDA2ExportAdapter): class SEDA2RelaxNGExport(RNGMixin, SEDA2ExportAdapter):
"""Abstract Adapter to build a Relax NG representation of a SEDA profile, using SEDA 2.1 """Abstract Adapter to build a Relax NG representation of a SEDA profile, using SEDA 2.1
specification.""" specification."""
__regid__ = "SEDA-2.1.rng" __regid__ = "SEDA-2.1.rng"
__abstract__ = True __abstract__ = True
...@@ -503,7 +503,7 @@ class SEDA2RelaxNGExport(RNGMixin, SEDA2ExportAdapter): ...@@ -503,7 +503,7 @@ class SEDA2RelaxNGExport(RNGMixin, SEDA2ExportAdapter):
def postprocess_dataobjectsreference(self, root, namespaces): def postprocess_dataobjectsreference(self, root, namespaces):
"""transform DataObjectReferenceId into DataObjectGroupReferenceId """transform DataObjectReferenceId into DataObjectGroupReferenceId
if wrap_dataobjects if wrap_dataobjects
""" """
return return
...@@ -752,23 +752,23 @@ class SEDA22RelaxNGExport(SEDA2RelaxNGExport): ...@@ -752,23 +752,23 @@ class SEDA22RelaxNGExport(SEDA2RelaxNGExport):
'rng:optional/rng:element[@name="DataObjectPackage"]', 'rng:optional/rng:element[@name="DataObjectPackage"]',
namespaces=namespaces, namespaces=namespaces,
) )
if dops: if dops:
assert len(dops) == 1 assert len(dops) == 1
dop = dops[0] dop = dops[0]
# insert DataObjectGroup to all descendent
# [Binary|Physical]DataObjects of DataObjectPackage will recieve a
nodes = dop.xpath( nodes = dop.xpath(
'rng:element[@name="BinaryDataObject" or @name="PhysicalDataObject"]', './descendant::rng:element[@name="BinaryDataObject" or @name="PhysicalDataObject"]',
namespaces=namespaces, namespaces=namespaces)
) if nodes:
opt_nodes = dop.xpath( zeroormore = self.element("rng:zeroOrMore")
'rng:optional[rng:element[@name="BinaryDataObject" or @name="PhysicalDataObject"]]', choice = self.element("rng:choice", zeroormore)
namespaces=namespaces, dop[0].addnext(zeroormore)
) for node in nodes:
if nodes or opt_nodes: parent = node.getparent()
# insert after definition of dop's id attribute if parent != dop:
for node in chain(nodes, opt_nodes): parent.getparent().remove(parent)
zeroormore = self.element("rng:zeroOrMore")
choice = self.element("rng:choice", zeroormore)
dop[0].addnext(zeroormore)
# insert DataObjectGroup with id from [Physical|Binary]DataObject if found # insert DataObjectGroup with id from [Physical|Binary]DataObject if found
group = self.element( group = self.element(
"rng:element", choice, attributes={"name": "DataObjectGroup"} "rng:element", choice, attributes={"name": "DataObjectGroup"}
...@@ -786,7 +786,7 @@ class SEDA22RelaxNGExport(SEDA2RelaxNGExport): ...@@ -786,7 +786,7 @@ class SEDA22RelaxNGExport(SEDA2RelaxNGExport):
def postprocess_dataobjectsreference(self, root, namespaces): def postprocess_dataobjectsreference(self, root, namespaces):
"""transform DataObjectReferenceId into DataObjectGroupReferenceId """transform DataObjectReferenceId into DataObjectGroupReferenceId
if wrap_dataobjects if wrap_dataobjects
""" """
# DataObjectReferenceId into DataObjectGroupReferenceId # DataObjectReferenceId into DataObjectGroupReferenceId
reference_nodes = root.xpath( reference_nodes = root.xpath(
...@@ -796,9 +796,11 @@ class SEDA22RelaxNGExport(SEDA2RelaxNGExport): ...@@ -796,9 +796,11 @@ class SEDA22RelaxNGExport(SEDA2RelaxNGExport):
) )
for reference_node in reference_nodes: for reference_node in reference_nodes:
reference_node.attrib["name"] = "DataObjectGroupReferenceId" reference_node.attrib["name"] = "DataObjectGroupReferenceId"
node_id = reference_node.xpath('@a:defaultValue[1]', namespaces=namespaces) node_id = reference_node.xpath("@a:defaultValue[1]", namespaces=namespaces)
# change defaultValue from BinaryDataObject xml:id to DataObjectGroup xml:id # change defaultValue from BinaryDataObject xml:id to DataObjectGroup xml:id
reference_node.attrib[f"{{{namespaces['a']}}}defaultValue"] = f"g{node_id[0]}" reference_node.attrib[
f"{{{namespaces['a']}}}defaultValue"
] = f"g{node_id[0]}"
class SEDA21RelaxNGExport(SEDA2RelaxNGExport): class SEDA21RelaxNGExport(SEDA2RelaxNGExport):
...@@ -824,19 +826,17 @@ class SEDA21RelaxNGExport(SEDA2RelaxNGExport): ...@@ -824,19 +826,17 @@ class SEDA21RelaxNGExport(SEDA2RelaxNGExport):
assert len(dops) == 1 assert len(dops) == 1
dop = dops[0] dop = dops[0]
nodes = dop.xpath( nodes = dop.xpath(
'rng:element[@name="BinaryDataObject" or @name="PhysicalDataObject"]', './descendant::rng:element[@name="BinaryDataObject" or @name="PhysicalDataObject"]',
namespaces=namespaces, namespaces=namespaces)
) if nodes:
opt_nodes = dop.xpath( zeroormore = self.element("rng:zeroOrMore")
'rng:optional[rng:element[@name="BinaryDataObject" or @name="PhysicalDataObject"]]', choice = self.element("rng:choice", zeroormore)
namespaces=namespaces, dop[0].addnext(zeroormore)
) for node in nodes:
if nodes or opt_nodes: parent = node.getparent()
group = self.element("rng:group") if parent != dop:
# insert after definition of dop's id attribute parent.getparent().remove(parent)
dop[0].addnext(group) choice.append(node)
for node in chain(nodes, opt_nodes):
group.append(node)
class XAttr( class XAttr(
......
...@@ -510,24 +510,33 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC): ...@@ -510,24 +510,33 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC):
dop = self.get_element(profile, "DataObjectPackage") dop = self.get_element(profile, "DataObjectPackage")
self.assertEqual(len(self.xpath(dop, "./rng:group/*")), 3) self.assertEqual(len(self.xpath(dop, "./rng:group/*")), 3)
def test_object_data_object_group(self): def test_object_data_object_with_group(self):
with self.admin_access.cnx() as cnx: with self.admin_access.cnx() as cnx:
transfer = cnx.create_entity( transfer = cnx.create_entity(
"SEDAArchiveTransfer", title=u"test profile", wrap_dataobjects=True "SEDAArchiveTransfer", title=u"test profile", wrap_dataobjects=True
) )
bdo = cnx.create_entity( cnx.create_entity(
"SEDABinaryDataObject", "SEDABinaryDataObject",
user_cardinality="1",
user_annotation=u"I am number one", user_annotation=u"I am number one",
seda_binary_data_object=transfer, seda_binary_data_object=transfer,
) )
cnx.create_entity( cnx.create_entity(
"SEDABinaryDataObject", "SEDAPhysicalDataObject",
user_cardinality="1..n",
user_annotation=u"I am number two", user_annotation=u"I am number two",
seda_physical_data_object=transfer,
)
cnx.create_entity(
"SEDABinaryDataObject",
user_cardinality="0..1",
user_annotation=u"I am number one",
seda_binary_data_object=transfer, seda_binary_data_object=transfer,
) )
cnx.create_entity( cnx.create_entity(
"SEDAPhysicalDataObject", "SEDAPhysicalDataObject",
user_annotation=u"I am number three", user_cardinality="0..n",
user_annotation=u"I am number two",
seda_physical_data_object=transfer, seda_physical_data_object=transfer,
) )
...@@ -551,19 +560,46 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC): ...@@ -551,19 +560,46 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC):
'/rng:element[@name="PhysicalDataObject"]', '/rng:element[@name="PhysicalDataObject"]',
) )
), ),
1, 2,
) )
# setting some cardinality to 1 will remove rng:optional parent of the DataObjectPackage
# and BinaryDataObject nodes def test_object_data_object_without_group(self):
bdo.cw_set(user_cardinality=u"1") with self.admin_access.cnx() as cnx:
transfer = cnx.create_entity(
"SEDAArchiveTransfer", title=u"test profile", wrap_dataobjects=False
)
cnx.create_entity(
"SEDABinaryDataObject",
user_cardinality="1",
user_annotation=u"I am number one",
seda_binary_data_object=transfer,
)
cnx.create_entity(
"SEDAPhysicalDataObject",
user_cardinality="1..n",
user_annotation=u"I am number two",
seda_physical_data_object=transfer,
)
cnx.create_entity(
"SEDABinaryDataObject",
user_cardinality="0..1",
user_annotation=u"I am number one",
seda_binary_data_object=transfer,
)
cnx.create_entity(
"SEDAPhysicalDataObject",
user_cardinality="0..n",
user_annotation=u"I am number two",
seda_physical_data_object=transfer,
)
profile = self.profile_etree(transfer) profile = self.profile_etree(transfer)
dop = self.get_element(profile, "DataObjectPackage") dop = self.get_element(profile, "DataObjectPackage")
self.assertEqual( self.assertEqual(
len( len(
self.xpath( self.xpath(
dop, dop,
'./rng:zeroOrMore/rng:choice/rng:element[@name="DataObjectGroup"]' './rng:zeroOrMore/rng:choice/rng:element[@name="BinaryDataObject"]',
'/rng:element[@name="BinaryDataObject"]',
) )
), ),
2, 2,
...@@ -572,11 +608,10 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC): ...@@ -572,11 +608,10 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC):
len( len(
self.xpath( self.xpath(
dop, dop,
'./rng:zeroOrMore/rng:choice/rng:element[@name="DataObjectGroup"]' './rng:zeroOrMore/rng:choice/rng:element[@name="PhysicalDataObject"]',
'/rng:element[@name="PhysicalDataObject"]',
) )
), ),
1, 2,
) )
def test_transfer_annotation(self): def test_transfer_annotation(self):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment