Basic export of simplified profile to SEDA 1.0 RNG
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 07 Oct 2016 18:04:58 +0200
changeset 1627 c88820fa450e
parent 1626 fd932a779c3b
child 1628 9393d8e2702f
Basic export of simplified profile to SEDA 1.0 RNG Related to #15524427
entities/profile_generation.py
test/data/seda_1_export.rng
test/test_profile_generation.py
--- a/entities/profile_generation.py	Fri Oct 07 17:51:46 2016 +0200
+++ b/entities/profile_generation.py	Fri Oct 07 18:04:58 2016 +0200
@@ -1197,6 +1197,53 @@
     kw_content_tag_attributes = [XAttr('languageID', 'xsd:language')]
 
 
+class SEDA1RNGExport(RNGMixin, SEDA1XSDExport):
+    """Adapter to build an RNG representation of a simplified SEDA profile, using SEDA 1.0
+    specification.
+    """
+    __regid__ = 'SEDA-1.0.rng'
+    __select__ = SEDA2XSDExport.__select__ & simplified_profile()
+    extension = 'rng'
+
+    namespaces = SEDA1XSDExport.namespaces.copy()
+    namespaces['rng'] = 'http://relaxng.org/ns/structure/1.0'
+    root_attributes = {
+        'ns': 'fr:gouv:culture:archivesdefrance:seda:v1.0',
+        'datatypeLibrary': 'http://www.w3.org/2001/XMLSchema-datatypes',
+    }
+
+    def xsd_element(self, parent, name, xsd_type=None, fixed_value=None, cardinality='1',
+                    documentation=None, xsd_attributes=()):
+        attributes = {'name': name}
+        if documentation:
+            attributes['documentation'] = documentation
+        parent = self.rng_element_parent(parent, *minmax_cardinality(cardinality))
+        element = self.element('rng:element', parent, attributes)
+        for xattr in xsd_attributes:
+            self.attribute_schema(element, xattr)
+
+        if xsd_type is not None:
+            self.rng_value(element, xsd_type, fixed_value)
+        else:
+            assert fixed_value is None
+        return element
+
+    def attribute_schema(self, parent, xattr):
+        if xattr.cardinality is None:
+            return  # XXX prohibit?
+        minimum = minmax_cardinality(xattr.cardinality, ('0..1', '1'))[0]
+        parent = self.rng_element_parent(parent, minimum)
+        attr = self.element('rng:attribute', parent, {'name': xattr.name})
+        self.rng_value(attr, xattr.qualified_type, xattr.fixed_value)
+
+    def dump_etree(self):
+        """Return an RNG etree for the adapted SEDA profile."""
+        root = self.element('rng:grammar', attributes=self.root_attributes)
+        start = self.element('rng:start', root)
+        self.xsd_transfer(start, self.entity)
+        return root
+
+
 def xsd_element_cardinality(occ, card_entity):
     """Return XSD element cardinality for the given pyxst Occurence. Cardinality may be overriden by
     the data model's user_cardinality value.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/seda_1_export.rng	Fri Oct 07 18:04:58 2016 +0200
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rng:grammar xmlns:rng="http://relaxng.org/ns/structure/1.0"
+             xmlns:clm60133="urn:un:unece:uncefact:codelist:standard:6:0133:40106"
+             xmlns:clmDAFFileTypeCode="urn:un:unece:uncefact:codelist:draft:DAF:fileTypeCode:2009-08-18"
+             xmlns:clmIANACharacterSetCode="urn:un:unece:uncefact:codelist:standard:IANA:CharacterSetCode:2007-05-14"
+             xmlns:clmIANAMIMEMediaType="urn:un:unece:uncefact:codelist:standard:IANA:MIMEMediaType:2008-11-12"
+             xmlns:qdt="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1"
+             xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10"
+             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+             ns="fr:gouv:culture:archivesdefrance:seda:v1.0"
+             datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <rng:start>
+    <rng:element name="ArchiveTransfer">
+      <xsd:annotation>
+        <xsd:documentation>my profile title &amp;&amp;</xsd:documentation>
+      </xsd:annotation>
+      <rng:element name="Comment">
+        <rng:value datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="TextType">my profile description &amp;&amp;</rng:value>
+      </rng:element>
+      <rng:element name="Date">
+        <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateTimeType"/>
+      </rng:element>
+      <rng:element name="TransferIdentifier">
+        <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="ArchivesIDType"/>
+      </rng:element>
+      <rng:oneOrMore>
+        <rng:element name="Archive">
+          <rng:element name="DescriptionLanguage">
+            <rng:attribute name="listVersionID">
+              <rng:value type="token">edition 2011</rng:value>
+            </rng:attribute>
+            <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeLanguageType">fra</rng:value>
+          </rng:element>
+          <rng:element name="Name">
+            <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="TextType"/>
+          </rng:element>
+          <rng:optional>
+            <rng:element name="Appraisal">
+              <xsd:annotation>
+                <xsd:documentation>detruire le document</xsd:documentation>
+              </xsd:annotation>
+              <rng:element name="Code">
+                <rng:attribute name="listVersionID">
+                  <rng:value type="token">edition 2009</rng:value>
+                </rng:attribute>
+                <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeAppraisalType">detruire</rng:value>
+              </rng:element>
+              <rng:element name="Duration">
+                <xsd:annotation>
+                  <xsd:documentation>C'est dans 10ans je m'en irai</xsd:documentation>
+                </xsd:annotation>
+                <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="ArchivesDurationType">P10Y</rng:value>
+              </rng:element>
+              <rng:element name="StartDate">
+                <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateType"/>
+              </rng:element>
+            </rng:element>
+          </rng:optional>
+          <rng:element name="AccessRestrictionRule">
+            <rng:element name="Code">
+              <rng:attribute name="listVersionID">
+                <rng:value type="token">edition 2009</rng:value>
+              </rng:attribute>
+              <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeAccessRestrictionType"/>
+            </rng:element>
+            <rng:element name="StartDate">
+              <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateType"/>
+            </rng:element>
+          </rng:element>
+          <rng:element name="ContentDescription">
+            <rng:element name="DescriptionLevel">
+              <rng:attribute name="listVersionID">
+                <rng:value type="token">edition 2009</rng:value>
+              </rng:attribute>
+              <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeDescriptionLevelType">file</rng:value>
+            </rng:element>
+            <rng:optional>
+              <rng:element name="OldestDate">
+                <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateType"/>
+              </rng:element>
+            </rng:optional>
+            <rng:optional>
+              <rng:element name="LatestDate">
+                <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateType"/>
+              </rng:element>
+            </rng:optional>
+            <rng:optional>
+              <rng:element name="Description">
+                <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="TextType"/>
+              </rng:element>
+            </rng:optional>
+            <rng:zeroOrMore>
+              <rng:element name="Keyword">
+                <rng:element name="KeywordContent">
+                  <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="KeywordContentType">file</rng:value>
+                </rng:element>
+                <rng:element name="KeywordReference">
+                  <rng:attribute name="schemeName">
+                    <rng:value type="string">seda_description_level/None vocabulary</rng:value>
+                  </rng:attribute>
+                  <rng:attribute name="schemeURI">
+                    <rng:value type="anyURI">%(scheme-uri)s</rng:value>
+                  </rng:attribute>
+                  <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="ArchivesIDType">%(concept-uri)s</rng:value>
+                </rng:element>
+              </rng:element>
+            </rng:zeroOrMore>
+          </rng:element>
+          <rng:oneOrMore>
+            <rng:element name="ArchiveObject">
+              <rng:element name="Name">
+                <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="TextType"/>
+              </rng:element>
+              <rng:optional>
+                <rng:element name="Appraisal">
+                  <rng:element name="Code">
+                    <rng:attribute name="listVersionID">
+                      <rng:value type="token">edition 2009</rng:value>
+                    </rng:attribute>
+                    <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeAppraisalType"/>
+                  </rng:element>
+                  <rng:element name="Duration">
+                    <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="ArchivesDurationType"/>
+                  </rng:element>
+                  <rng:element name="StartDate">
+                    <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateType"/>
+                  </rng:element>
+                </rng:element>
+              </rng:optional>
+              <rng:element name="AccessRestrictionRule">
+                <xsd:annotation>
+                  <xsd:documentation>restrict</xsd:documentation>
+                </xsd:annotation>
+                <rng:element name="Code">
+                  <rng:attribute name="listVersionID">
+                    <rng:value type="token">edition 2009</rng:value>
+                  </rng:attribute>
+                  <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeAccessRestrictionType">AR038</rng:value>
+                </rng:element>
+                <rng:element name="StartDate">
+                  <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="DateType"/>
+                </rng:element>
+              </rng:element>
+              <rng:element name="ContentDescription">
+                <rng:element name="DescriptionLevel">
+                  <rng:attribute name="listVersionID">
+                    <rng:value type="token">edition 2009</rng:value>
+                  </rng:attribute>
+                  <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeDescriptionLevelType"/>
+                </rng:element>
+              </rng:element>
+            </rng:element>
+          </rng:oneOrMore>
+          <rng:oneOrMore>
+            <rng:element name="ArchiveObject">
+              <rng:element name="Name">
+                <rng:data datatypeLibrary="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:10" type="TextType"/>
+              </rng:element>
+              <rng:element name="ContentDescription">
+                <rng:element name="DescriptionLevel">
+                  <rng:attribute name="listVersionID">
+                    <rng:value type="token">edition 2009</rng:value>
+                  </rng:attribute>
+                  <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeDescriptionLevelType"/>
+                </rng:element>
+              </rng:element>
+            </rng:element>
+          </rng:oneOrMore>
+          <rng:zeroOrMore>
+            <rng:element name="Document">
+              <rng:element name="Attachment">
+                <rng:attribute name="format">
+                  <rng:value datatypeLibrary="urn:un:unece:uncefact:codelist:draft:DAF:fileTypeCode:2009-08-18" type="FileTypeCodeType">fmt/123</rng:value>
+                </rng:attribute>
+                <rng:attribute name="encodingCode">
+                  <rng:value datatypeLibrary="urn:un:unece:uncefact:codelist:standard:6:0133:40106" type="CharacterSetEncodingCodeContentType">6</rng:value>
+                </rng:attribute>
+                <rng:data datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="ArchivesBinaryObjectType"/>
+              </rng:element>
+              <rng:element name="Type">
+                <rng:attribute name="listVersionID">
+                  <rng:value type="token">edition 2009</rng:value>
+                </rng:attribute>
+                <rng:value datatypeLibrary="fr:gouv:culture:archivesdefrance:seda:v1.0:QualifiedDataType:1" type="CodeDocumentType">CDO</rng:value>
+              </rng:element>
+            </rng:element>
+          </rng:zeroOrMore>
+        </rng:element>
+      </rng:oneOrMore>
+    </rng:element>
+  </rng:start>
+</rng:grammar>
--- a/test/test_profile_generation.py	Fri Oct 07 17:51:46 2016 +0200
+++ b/test/test_profile_generation.py	Fri Oct 07 18:04:58 2016 +0200
@@ -666,7 +666,7 @@
         self.assertEqual(set(elmt.attrib['type'] for elmt in ddt), set(['date', 'dateTime']))
 
 
-class SEDA1XSDExportTC(XMLSchemaTestMixin, CubicWebTC):
+class OldSEDAExportMixin(object):
     def setup_database(self):
         with self.admin_access.client_cnx() as cnx:
             create = cnx.create_entity
@@ -777,32 +777,45 @@
         self.transfer_eid = transfer.eid
         self.file_concept_eid = concepts['file'].eid
 
-    def test_seda_1_0(self):
-        self._test_profile_xsd('SEDA-1.0.xsd', 'seda_1_export.xsd')
-
-    def test_seda_0_2(self):
-        self._test_profile_xsd('SEDA-0.2.xsd', 'seda_02_export.xsd')
-
-    def _test_profile_xsd(self, adapter_id, expected_file):
+    def _test_profile(self, adapter_id, expected_file):
         with self.admin_access.client_cnx() as cnx:
             transfer = cnx.entity_from_eid(self.transfer_eid)
             adapter = transfer.cw_adapt_to(adapter_id)
             generated_xsd = adapter.dump()
             open('/tmp/x.xml', 'w').write(generated_xsd)
-            xml = etree.fromstring(generated_xsd)
-            self.assertXmlValid(xml)
+            root = etree.fromstring(generated_xsd)
+            self.assertXmlValid(root)
             file_concept = cnx.entity_from_eid(self.file_concept_eid)
             with open(self.datapath(expected_file)) as expected:
                 self.assertXmlEqual(expected.read()
                                     % {'concept-uri': binary_type(file_concept.cwuri),
                                        'scheme-uri': binary_type(file_concept.scheme.cwuri)},
                                     generated_xsd)
-            # ensure there is no element with @type but a complex type
-            namespaces = adapter.namespaces.copy()
-            namespaces.pop(None)
-            dates = xml.xpath('//xsd:element[@name="Date"]/xsd:complexType/xsd:sequence',
-                              namespaces=namespaces)
-            self.assertEqual(len(dates), 0)
+            return adapter, root
+
+
+class OldSEDAXSDExportTC(XMLSchemaTestMixin, OldSEDAExportMixin, CubicWebTC):
+
+    def test_seda_1_0(self):
+        self._test_profile('SEDA-1.0.xsd', 'seda_1_export.xsd')
+
+    def test_seda_0_2(self):
+        self._test_profile('SEDA-0.2.xsd', 'seda_02_export.xsd')
+
+    def _test_profile(self, adapter_id, expected_file):
+        adapter, root = super(OldSEDAXSDExportTC, self)._test_profile(adapter_id, expected_file)
+        # ensure there is no element with @type but a complex type
+        namespaces = adapter.namespaces.copy()
+        namespaces.pop(None)
+        dates = root.xpath('//xsd:element[@name="Date"]/xsd:complexType/xsd:sequence',
+                           namespaces=namespaces)
+        self.assertEqual(len(dates), 0)
+
+
+class OldSEDARNGExportTC(RelaxNGTestMixin, OldSEDAExportMixin, CubicWebTC):
+
+    def test_seda_1_0(self):
+        self._test_profile('SEDA-1.0.rng', 'seda_1_export.rng')
 
 
 if __name__ == '__main__':