Code Sets Demo

Let’s demonstrate different ways “external” CodeSet schema can be used to validate code values in a message. This table summarise what works.
☑ = works – detects that code value in message is invalid.

Method based on
string
based on
source code set
Message Schema
alone
Checks format,
not value.
Checks format,
not value.
Include codeset
by reference
☒ duplicate
declaration
☑ Checks value if xsi:type specified.
Import codeset
by reference
Checks format,
not value,
as codeset unused
☑ Checks value if xsi:type specified
Redefine CodeSet
by copy
Redefine use of
by reference
☒ can’t redefine as different base.
Override CodeSet
by reference
☑ include into namespace, and add base type based on string.
Override use of
by reference

Example message

Let’s explore the options with a simple example with an invalid CODE.
This example is from the 2019 Message Definition Report Part 1 for
Securities Account Reference Data messages, but with the proprietary reason replaced with what should be a standard “external” reason code.

7.4.3 Securities Account Status Advice – reda.020.001.01 – Rejected example

<Document xmlns="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01 reda.020.001.01.xsd">
 <SctiesAcctStsAdvc>
  <MsgHdr>
   <MsgId>NONREF</MsgId>
   <OrgnlBizInstr>
    <MsgId>SAMPLESACDELETE</MsgId>
   </OrgnlBizInstr>
  </MsgHdr>
  <SctiesAcctSts>
   <Sts>REJT</Sts>
   <StsRsn>
    <Rsn>
     <Cd>CODE</Cd>
    </Rsn>
    <AddtlInf>ABCD000 DELETION REJECTED</AddtlInf>
   </StsRsn>
  </SctiesAcctSts>
 </SctiesAcctStsAdvc>
</Document>

Message Schema alone simply check the format of the value,
not the value itself, as the “external” CodeSet is not enumerated.

To check the code is a valid value, we use a “head” schema file that combines the Message and Code Set schema files.

Code Set schema files define the valid enumerations.
They are based either on xsd:string, or derived from a source code set type.
The methods are implemented slightly differently in each case.

Code Set based on string

/Document/SctiesAcctStsAdvc/SctiesAcctSts/StsRsn/Rsn/Cd
in the message schema has type “ExternalStatusReason1Code”,
an “external” logical Code Set without enumerated values.

The “external” Code Set schema enumerates values restricting string.

<xs:schema ...>
 <xs:simpleType name="ExternalStatusReason1Code">
  <xs:restriction base="xs:string">
   <xs:minLength value="1"/>
   <xs:maxLength value="4"/>
   <xs:enumeration value="AB02"/>
   ...

Methods

  • Include code set by reference doesn’t work, because declaring ExternalStatusReason1Code twice maked the schema invalid.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
 ...>
 <xs:include schemaLocation="reda.020.001.01.xsd"/>
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
</xs:schema>
  • Import codeset by reference doesn’t work check the value, because
    <Cd> doesn’t refernece the type in the new namespace.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01"  ...>
 <xs:include schemaLocation="reda.020.001.01.xsd"/>
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" schemaLocation="ExternalStatusReason1Code(20191018)+ns.xsd"/>
</xs:schema>
  • Redefine CodeSet by copy works because the original type is redefined. However, this requires a copy in the new schema.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
 ...>
 <xs:redefine schemaLocation="reda.020.001.01.xsd">
  <xs:simpleType name="ExternalStatusReason1Code">
   <xs:restriction base="ExternalStatusReason1Code">
    <xs:enumeration value="AB02"/>
    ...
  • Redefine use of the code set doesn’t work, because the replacement type is not based on the original type.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
  xmlns:code="urn:iso:std:iso:20022:tech:xsd:externalcodeset" ...>
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" schemaLocation="ExternalStatusReason1Code(20191018)+ns.xsd"/>
 <xs:redefine schemaLocation="reda.020.001.01.xsd">
  <xs:complexType name="StatusReason6Choice">
   <xs:complexContent>
    <xs:restriction base="StatusReason6Choice">
     <xs:choice>
      <xs:element name="Cd" type="code:ExternalStatusReason1Code"/>
      <xs:element name="Prtry" type="Max35Text"/>
     </xs:choice>
    </xs:restriction>
   </xs:complexContent>
  </xs:complexType>
 </xs:redefine>
</xs:schema>
  • Override CodeSet by reference works, requiring XSD 1.1.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01"   
  xmlns:code="urn:iso:std:iso:20022:tech:xsd:externalcodeset" 
  vc:minVersion="1.1" ... >
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" schemaLocation="ExternalStatusReason1Code(20191018)+ns.xsd"/>
 <xs:override schemaLocation="reda.020.001.01.xsd">
  <xs:simpleType name="ExternalStatusReason1Code">
   <xs:restriction base="code:ExternalStatusReason1Code"/>
  </xs:simpleType>
 </xs:override>
</xs:schema>
  • Override use of Code Set by reference works, requiring XSD 1.1.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01"   
  xmlns:code="urn:iso:std:iso:20022:tech:xsd:externalcodeset" 
  vc:minVersion="1.1" ... >
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" schemaLocation="ExternalStatusReason1Code(20191018_Sample)+ns.xsd"/>
 <xs:override schemaLocation="reda.020.001.01.xsd">
  <xs:complexType name="StatusReason6Choice">
   <xs:choice>
    <xs:element name="Cd" type="code:ExternalStatusReason1Code"/>
    <xs:element name="Prtry" type="Max35Text"/>
   </xs:choice>
  </xs:complexType>
 </xs:override>
</xs:schema>

Code Set based on Source Code Set

/Document/SctiesAcctStsAdvc/SctiesAcctSts/StsRsn/Rsn/Cd
in the message schema has type “ExternalStatusReasonCode”, (name edited)
a “source” conceptual Code Set without enumerated values.

The “derived” logical Code Set schema file enumerates values restricting the
“source” conceptual Code Set “ExternalStatusReasonCode”.

<xs:schema ...>
 <xs:simpleType name="ExternalStatusReason1Code">
  <xs:restriction base="ExternalStatusReasonCode">
   <xs:minLength value="1"/>
   <xs:maxLength value="4"/>
   <xs:enumeration value="AB02"/>
   ...

Methods

Both importing and including the code set check values if the message instance specifies an xsi:type with enumerations. This can be useful in scenarios where a bespoke code set is desired as an alternative.

  • Include code set by reference only check the values if the message instance specifies an xsi:type with enumerations.
   <Cd xsi:type="ExternalStatusReason1Code">CODE</Cd>
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
 ...>
 <xs:include schemaLocation="reda.020.001.01.xsd"/>
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
</xs:schema>
  • Import code set by reference only check the values if the message instance specifies an xsi:type with enumerations.
    As it’s imported, it has a different namespace.
    <Cd xsi:type="code:ExternalStatusReason1Code">CODE</Cd>

Also, an extra level is required to link the code: base type to the one declared in the namespace of the message.

<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
  ... >
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" schemaLocation="ExternalStatusReason1Code(20191018)+base.xsd"/>
</xs:schema>

<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" xmlns:message="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" ... >
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" schemaLocation="reda.020.001.01.xsd"/>
 <xs:simpleType name="ExternalStatusReasonCode">
  <xs:restriction base="message:ExternalStatusReasonCode"/>
 </xs:simpleType>
</xs:schema>
  • Redefine CodeSet by copy works because the original type is redefined. However, this requires a copy in the new schema.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
 ...>
 <xs:redefine schemaLocation="reda.020.001.01.xsd">
  <xs:simpleType name="ExternalStatusReasonCode">
   <xs:restriction base="ExternalStatusReasonCode">
    <xs:enumeration value="AB02"/>
    ...
  • Redefine use of the code set works this time,
    because the replacement type is based on the original type.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
  xmlns:code="urn:iso:std:iso:20022:tech:xsd:externalcodeset" ...>
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
 <xs:redefine schemaLocation="reda.020.001.01.xsd">
  <xs:complexType name="StatusReason6Choice">
   <xs:complexContent>
    <xs:restriction base="StatusReason6Choice">
     <xs:choice>
      <xs:element name="Cd" type="ExternalStatusReason1Code"/>
      <xs:element name="Prtry" type="Max35Text"/>
     </xs:choice>
    </xs:restriction>
   </xs:complexContent>
  </xs:complexType>
 </xs:redefine>
</xs:schema>
  • Override CodeSet by reference works, requiring XSD 1.1.
    As this overrides the base type with a derived type, to prevent a circular dependency we base it on string in a new name space.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01" 
  xmlns:code="urn:iso:std:iso:20022:tech:xsd:externalcodeset" " 
  vc:minVersion="1.1" ... >
 <xs:import namespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" schemaLocation="ExternalStatusReason1Code(20191018)+string.xsd"/>
 <xs:override schemaLocation="reda.020.001.01.xsd">
  <xs:simpleType name="ExternalStatusReasonCode">
   <xs:restriction base="code:ExternalStatusReason1Code"/>
  </xs:simpleType>
 </xs:override>
</xs:schema>

<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:externalcodeset" 
  xmlns:message="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01"   ... >
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
 <xs:simpleType name="ExternalStatusReasonCode">
  <xs:restriction base="xs:string"/>
 </xs:simpleType>
</xs:schema>
  • Override use of Code Set by reference works, requiring XSD 1.1.
<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01"  
  vc:minVersion="1.1" ... >
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
 <xs:override schemaLocation="reda.020.001.01.xsd">
  <xs:complexType name="StatusReason6Choice">
   <xs:choice>
    <xs:element name="Cd" type="ExternalStatusReason1Code"/>
    <xs:element name="Prtry" type="Max35Text"/>
   </xs:choice>
  </xs:complexType>
 </xs:override>
</xs:schema>

Discussion

We’ve demonstrated that there are severel methods to check the value of codes in messages. Use the right method for the desired result.

If you don’t want check external codes, just use the message schema.

If you want to check external codes, only when an xsi:type is specified,
then use a head schema that includes or imports the code set schema
with the code set’s base type set to the element’s type.

With XSD 1.0,
If you want to always check external codes from consistent code sets:
redefine the Code Set by copying enumerations into a head schema.
If you want to always check external codes differently for each element,
redefine the element’s type to a code set based on it.

With XSD 1.1,
If you want to always check external codes from consistent code sets:
override the defintition of the codeset with a code set based on string.
If you want to always check external codes differently for each element,
override definition of the element’s type to your code set.

Conclusion

The simplest approach to always check external codes consistently,
is to override the definition of the Code Set, with a Code Set based on string.

<xs:schema targetNamespace="urn:iso:std:iso:20022:tech:xsd:reda.020.001.01"   
  vc:minVersion="1.1" ... >
 <xs:include schemaLocation="ExternalStatusReason1Code(20191018).xsd"/>
 <xs:override schemaLocation="reda.020.001.01.xsd">
  <xs:simpleType name="ExternalStatusReasonCode">
   <xs:restriction base="ExternalStatusReason1Code"/>
  </xs:simpleType>
 </xs:override>
</xs:schema>

Recommendation

For a message design to enable selection of Code Sets by configuration,
a Message Attribute should use a conceptual code set. This should be generated as an unenumerated restriction on xsd:string.

Conceptual Code Set schema should be generated as enumerated restrictions on xsd:string.

Logical Code Set schema should be generated based on the generated type of the conceptual Code Set.

This approach provides the most flexibility to implementers,
allowing configured head schema to validate using conceptual and/or logical Code Set schema.