Commit 6c2d8ff8 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

[profile gen] Ensure same name children are ordered accorded to their cardinality

As explained in the previous commit, we want items with cardinality = 1 first
then the one with cardinality != 1 if any. See previous commit for detailed
explanation.

Closes #17098404
parent 39d1d971e058
......@@ -162,6 +162,10 @@ def attribute_minimum_cardinality(occ, card_entity):
return minmax_cardinality(cardinality, ('0..1', '1'))[0]
# sort on user_cardinality != 1 to have all entities with cardinality == 1 first
_sorted_children = partial(sorted, key=lambda x: getattr(x, 'user_cardinality', '1') != '1')
def iter_path_children(xselement, entity):
"""Return an iterator on `entity` children entities according to `xselement` definition.
......@@ -174,7 +178,7 @@ def iter_path_children(xselement, entity):
if getattr(entity, rtype) is not None:
yield _path, getattr(entity, rtype)
else:
related = entity.related(rtype, role, entities=True)
related = _sorted_children(entity.related(rtype, role, entities=True))
if related:
yield _path, related
......@@ -738,7 +742,7 @@ class SEDA1XSDExport(SEDA2ExportAdapter):
def xsd_transfer(self, parent, archive_transfer):
"""Append XSD elements for the archive transfer to the given parent node."""
transfer_node = self.xsd_transfer_base(parent, archive_transfer)
for archive_unit in archive_transfer.archive_units:
for archive_unit in _sorted_children(archive_transfer.archive_units):
self.xsd_archive(transfer_node, archive_unit)
def xsd_archive(self, parent, archive_unit):
......@@ -822,7 +826,9 @@ class SEDA1XSDExport(SEDA2ExportAdapter):
archive objects or documents, and append XSD elements for them to the given parent node.
"""
for au_or_bdo in sorted(entity.cw_adapt_to('ITreeBase').iterchildren(),
key=lambda x: (x.cw_etype == self.last_children_type, x.eid)):
key=lambda x: (x.cw_etype == self.last_children_type,
x.user_cardinality != '1',
x.eid)):
if au_or_bdo.cw_etype == 'SEDABinaryDataObject':
self.xsd_document(parent, au_or_bdo)
else:
......@@ -1014,14 +1020,14 @@ class SEDA1XSDExport(SEDA2ExportAdapter):
xsd_attributes=[XAttr('languageID', 'xsd:language')])
def xsd_keywords(self, parent, content):
for keyword in content.keywords:
for keyword in _sorted_children(content.keywords):
self.xsd_keyword(parent, keyword)
def xsd_custodial_history(self, parent, content):
if content.custodial_history_items:
ch_node = self.element_schema(parent, 'CustodialHistory',
cardinality='0..1')
for item in content.custodial_history_items:
for item in _sorted_children(content.custodial_history_items):
when_card = item.when.user_cardinality if item.when else None
self.element_schema(ch_node, 'CustodialHistoryItem', 'qdt:CustodialHistoryItemType',
cardinality=item.user_cardinality,
......@@ -1140,10 +1146,10 @@ class SEDA02XSDExport(SEDA1XSDExport):
"""Append XSD elements for the archive transfer to the given parent node."""
transfer_node = self.xsd_transfer_base(parent, archive_transfer)
for data_object in archive_transfer.binary_data_objects:
for data_object in _sorted_children(archive_transfer.binary_data_objects):
self.xsd_integrity(transfer_node, data_object)
for archive_unit in archive_transfer.archive_units:
for archive_unit in _sorted_children(archive_transfer.archive_units):
self.xsd_archive(transfer_node, archive_unit)
def xsd_archive(self, parent, archive_unit):
......@@ -1340,7 +1346,7 @@ def _simple_path_target_values(entity, rtype, role, target_etype):
if rtype == 'id':
return [(None, eid2xmlid(entity.eid))]
return [(None, getattr(entity, rtype, None))]
targets = entity.related(rtype, role, entities=True)
targets = _sorted_children(entity.related(rtype, role, entities=True))
rschema = entity._cw.vreg.schema.rschema
rdefschema = next(iter(rschema(rtype).rdefs.values()))
# data_object_reference_id is artificially composite to ease the case of simplified profile
......@@ -1371,7 +1377,7 @@ def _complex_path_target_values(entity, path):
rtype_targets.append((entity, getattr(entity, rtype, None)))
else:
try:
targets = entity.related(rtype, role, entities=True)
targets = _sorted_children(entity.related(rtype, role, entities=True))
except KeyError:
# the relation is not defined in the schema: element is not modelized but should
# be added in the XSD
......
......@@ -402,72 +402,6 @@
</rng:element>
</rng:element>
</rng:zeroOrMore>
<rng:oneOrMore>
<rng:element name="Contains">
<rng:element name="DescriptionLevel">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">file</rng:value>
</rng:element>
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Name">
<rng:optional>
<rng:attribute name="languageID">
<rng:data type="language"/>
</rng:attribute>
</rng:optional>
<rng:data type="string"/>
</rng:element>
<rng:optional>
<rng:element name="Appraisal">
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:data type="string"/>
</rng:element>
<rng:element name="Duration">
<rng:data type="string"/>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:optional>
<rng:element name="AccessRestriction">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">AR038</rng:value>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:element>
</rng:oneOrMore>
<rng:element name="Contains">
<rng:element name="DescriptionLevel">
<rng:attribute name="listVersionID">
......@@ -535,6 +469,72 @@
</rng:element>
</rng:element>
</rng:element>
<rng:oneOrMore>
<rng:element name="Contains">
<rng:element name="DescriptionLevel">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">file</rng:value>
</rng:element>
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Name">
<rng:optional>
<rng:attribute name="languageID">
<rng:data type="language"/>
</rng:attribute>
</rng:optional>
<rng:data type="string"/>
</rng:element>
<rng:optional>
<rng:element name="Appraisal">
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:data type="string"/>
</rng:element>
<rng:element name="Duration">
<rng:data type="string"/>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:optional>
<rng:element name="AccessRestriction">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">AR038</rng:value>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:element>
</rng:oneOrMore>
</rng:element>
</rng:oneOrMore>
</rng:element>
......
......@@ -307,7 +307,7 @@
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element maxOccurs="unbounded" name="Contains">
<xsd:element name="Contains">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
......@@ -332,9 +332,12 @@
</xsd:complexType>
</xsd:element>
<xsd:element minOccurs="0" name="Appraisal">
<xsd:annotation>
<xsd:documentation>detruire le document</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Code">
<xsd:element fixed="detruire" name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAppraisalType">
......@@ -343,19 +346,20 @@
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="Duration" type="qdt:ArchivesDurationType"/>
<xsd:element fixed="P10Y" name="Duration" type="qdt:ArchivesDurationType">
<xsd:annotation>
<xsd:documentation>C'est dans 10ans je m'en irai</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="StartDate" type="udt:DateType"/>
</xsd:sequence>
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="AccessRestriction">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element fixed="AR038" name="Code">
<xsd:element name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAccessRestrictionType">
......@@ -373,7 +377,7 @@
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="Contains">
<xsd:element maxOccurs="unbounded" name="Contains">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
......@@ -398,12 +402,9 @@
</xsd:complexType>
</xsd:element>
<xsd:element minOccurs="0" name="Appraisal">
<xsd:annotation>
<xsd:documentation>detruire le document</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element fixed="detruire" name="Code">
<xsd:element name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAppraisalType">
......@@ -412,20 +413,19 @@
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element fixed="P10Y" name="Duration" type="qdt:ArchivesDurationType">
<xsd:annotation>
<xsd:documentation>C'est dans 10ans je m'en irai</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Duration" type="qdt:ArchivesDurationType"/>
<xsd:element name="StartDate" type="udt:DateType"/>
</xsd:sequence>
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="AccessRestriction">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Code">
<xsd:element fixed="AR038" name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAccessRestrictionType">
......
......@@ -360,85 +360,6 @@
<rng:data type="string"/>
</rng:element>
</rng:element>
<rng:oneOrMore>
<rng:element name="ArchiveObject">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Name">
<rng:optional>
<rng:attribute name="languageID">
<rng:data type="language"/>
</rng:attribute>
</rng:optional>
<rng:data type="string"/>
</rng:element>
<rng:element name="ContentDescription">
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="DescriptionLevel">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">file</rng:value>
</rng:element>
<rng:element name="Language">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:data type="string"/>
</rng:element>
</rng:element>
<rng:optional>
<rng:element name="Appraisal">
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:data type="string"/>
</rng:element>
<rng:element name="Duration">
<rng:data type="string"/>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:optional>
<rng:element name="AccessRestrictionRule">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">AR038</rng:value>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:element>
</rng:oneOrMore>
<rng:element name="ArchiveObject">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
......@@ -519,6 +440,85 @@
</rng:element>
</rng:element>
</rng:element>
<rng:oneOrMore>
<rng:element name="ArchiveObject">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Name">
<rng:optional>
<rng:attribute name="languageID">
<rng:data type="language"/>
</rng:attribute>
</rng:optional>
<rng:data type="string"/>
</rng:element>
<rng:element name="ContentDescription">
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="DescriptionLevel">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">file</rng:value>
</rng:element>
<rng:element name="Language">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:data type="string"/>
</rng:element>
</rng:element>
<rng:optional>
<rng:element name="Appraisal">
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:data type="string"/>
</rng:element>
<rng:element name="Duration">
<rng:data type="string"/>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:optional>
<rng:element name="AccessRestrictionRule">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<rng:optional>
<rng:attribute name="Id">
<rng:data type="ID"/>
</rng:attribute>
</rng:optional>
<rng:element name="Code">
<rng:attribute name="listVersionID">
<rng:value type="token">edition 2009</rng:value>
</rng:attribute>
<rng:value type="string">AR038</rng:value>
</rng:element>
<rng:element name="StartDate">
<rng:data type="string"/>
</rng:element>
</rng:element>
</rng:element>
</rng:oneOrMore>
<rng:zeroOrMore>
<rng:element name="Document">
<xsd:annotation>
......
......@@ -251,7 +251,7 @@
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element maxOccurs="unbounded" name="ArchiveObject">
<xsd:element name="ArchiveObject">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
......@@ -292,9 +292,12 @@
</xsd:complexType>
</xsd:element>
<xsd:element minOccurs="0" name="Appraisal">
<xsd:annotation>
<xsd:documentation>detruire le document</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Code">
<xsd:element fixed="detruire" name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAppraisalType">
......@@ -303,19 +306,20 @@
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="Duration" type="qdt:ArchivesDurationType"/>
<xsd:element fixed="P10Y" name="Duration" type="qdt:ArchivesDurationType">
<xsd:annotation>
<xsd:documentation>C'est dans 10ans je m'en irai</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="StartDate" type="udt:DateType"/>
</xsd:sequence>
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="AccessRestrictionRule">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element fixed="AR038" name="Code">
<xsd:element name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAccessRestrictionType">
......@@ -333,7 +337,7 @@
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="ArchiveObject">
<xsd:element maxOccurs="unbounded" name="ArchiveObject">
<xsd:annotation>
<xsd:documentation>archive unit title</xsd:documentation>
</xsd:annotation>
......@@ -374,12 +378,9 @@
</xsd:complexType>
</xsd:element>
<xsd:element minOccurs="0" name="Appraisal">
<xsd:annotation>
<xsd:documentation>detruire le document</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element fixed="detruire" name="Code">
<xsd:element name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAppraisalType">
......@@ -388,20 +389,19 @@
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element fixed="P10Y" name="Duration" type="qdt:ArchivesDurationType">
<xsd:annotation>
<xsd:documentation>C'est dans 10ans je m'en irai</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Duration" type="qdt:ArchivesDurationType"/>
<xsd:element name="StartDate" type="udt:DateType"/>
</xsd:sequence>
<xsd:attribute name="Id" type="xsd:ID" use="optional"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="AccessRestrictionRule">
<xsd:annotation>
<xsd:documentation>restrict</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Code">
<xsd:element fixed="AR038" name="Code">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="qdt:CodeAccessRestrictionType">
......
......@@ -448,6 +448,7 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC):
unit, unit_alt, unit_alt_seq = testutils.create_archive_unit(
transfer, user_cardinality=u'0..n')
create('SEDAKeyword', user_cardinality=u'0..n', seda_keyword=unit_alt_seq)
kw = create('SEDAKeyword', seda_keyword=unit_alt_seq,
keyword_content=u'kwick')
kwr_e = create('SEDAKeywordReference', seda_keyword_reference_from=kw)
......@@ -456,10 +457,19 @@ class SEDA2RNGExportTC(RelaxNGTestMixin, CubicWebTC):
profile = self.profile_etree(transfer)
kwc = self.get_element(profile, 'KeywordContent')
self.assertElementDefinition(kwc, {'name': 'KeywordContent',
'type': 'xsd:string',
'fixed': 'kwick'})
keywords = self.get_elements(profile, 'Keyword')
self.assertElementDefinition(keywords[0], {'name': 'Keyword'})
self.assertElementDefinition(keywords[1], {'name': 'Keyword',