681453450 Данный документ определяет правила заполнения xml-файла, описывающего структуру сообщений системы SWIFT. Рекомендованное имя xml-файла – SwiftMessageStructure.xml. Этот xml-файл (иногда называемый в тексте также «файлом-описателем») используется: парсером – при конвертации сообщения из формата DOS PCC в формат SwiftXml, и композером – при конвертации сообщения из формата SwiftXml в формат DOS PCC. Кроме того, в данном документе вскользь описываются некоторые принципы работы парсера и композера – в тех случаях, когда знание этих принципов облегчает понимание структуры «файла-описателя». Обозначения: Символом помечаются фрагменты текста, описывающие различные правила, выполнение которых проверяется при валидации (стандартной или расширенной) файла-описателя. Символ интерпретируется как «Обратите внимание». Термины. Блок Поле Формат поля в «свифтовой» нотации Атомарное (простое) поле Тэг Фрагмент dospcc-сообщения вида {N:……}, где N – цифра или буква (имя блока). Блок является самой крупной единицей внутренней структуры swift-сообщения; преобразуется парсером в элемент <Block>. В состав блока могут входить как «поля», так и «тэги» (см. далее). Фрагмент dospcc-сообщения, преобразуемый парсером в элемент <Field>. Может иметь сложную (составную) структуру, т.е. содержать в себе другие поля (именуемые в таком случае под-полями). Поле может быть многострочным. Строка вида :4!c/, [4*35x], 4!a2!a2!c[3!c] и т.п. Примеры форматов: 5n - обязательное поле, [5n] - опциональное поле, 4*35x - многострочное поле, 5n - атомарное (простое) поле, 5n2a - сложное (составное) поле. Поле, не содержащее в себе вложенных под-полей. Формат такого поля имеет вид :4!c/, 5n, 2-7a, [4*35x], но не 4!a2!a2!c[3!c]. Фрагмент dospcc-сообщения, преобразуемый парсером в элемент <Tag>. Состоит из последовательности полей, никак не отделённых друг от друга и без указания имён полей. Имя каждого тэга обрамляется с обеих сторон двоеточием, и перед стартовым двоеточием ещё идёт перенос строки (символы CRLF). Примеры: :32A:080827USD1, :70:JULIUS BAER MULTISTOCK CENTRAL EUROPE STOCK FUND, 39726. Блок «позиционного» формата Блок формата «именованных полей» Блок, в состав которого входят поля, никак не отделённые друг от друга и без указания имён полей. Примеры: {1:F21ATILCY2NAXXX0158129890}, {2:O5350318090120CHASGB2LDGST08421990020901200706N}. Блок, в состав которого входят поля, заключённые в фигурные скобки, внутри которых указано имя поля. Примеры: {5:{MAC:00000000}{CHK:9D052EBB2825}{DLM:}}, {S:{SAC:}{COP:S}}, {4:{177:0901200806}{451:0}}. Только в блоках формата «именованных полей» допускаются пустые поля (в примере выше – поля «DLM» и «SAC»). Page 1 of 12 681453450 Блок «тэгового» формата Реестр полей Описатель поля Блок, в состав которого входят тэги. После последнего тэга идёт перенос строки и символ «тире». Пример: {4: :20:112233 :23B:070707 :32A:080827USD1, :50A:/400919230 ATILCY2N :53B:/400919230 :57A:ATONRUM0 :59:/36249035 RBC DEXIA INVESTOR SERVICES BANK :70:JULIUS BAER MULTISTOCK CENTRAL EUROPE STOCK FUND, 39726 :71A:OUR -} Раздел файла-описателя SwiftMessageStructure/Fields/FieldInfo. Любой элемент <FieldInfo>, содержащийся в файле-описателе. Структура файла SwiftMessageStructure.xml определяется xml-схемой SwiftMessageStructure.xsd. Вот пример валидного файла SwiftMessageStructure.xml (содержимое сильно сокращено): <?xml version="1.0" encoding="utf-8"?> <SwiftMessageStructure xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SwiftMessageStructure.xsd"> <Blocks> <BlockInfo name="1"> <FieldInfo ref="ApplicationID" /> <FieldInfo ref="ServiceID" /> <FieldInfo ref="LTID" /> <FieldInfo ref="SessionNumber" /> <FieldInfo ref="SequenceNumber" /> </BlockInfo> </Blocks> <Fields> <!-- Для блока 1: --> <FieldInfo name="ApplicationID" format="1!a" /> <FieldInfo name="ServiceID" format="2!n" /> <FieldInfo name="LTID" format="12!c" /> <FieldInfo name="SessionNumber" format="4!n" /> <FieldInfo name="SequenceNumber" format="6!n" /> <!-- Для блока 4: --> <FieldInfo name="Qualifier" format=":4!c/" /> <FieldInfo name="OneSpace" format="1!e" /> <FieldInfo name="Sign" format="1!N" /> </Fields> <FieldTypes> <FieldType name="Date" format="6!n" dt:dt="Date" descr="Date in the <FieldType name="LongDate" format="8!n" dt:dt="Date" descr="Date in <FieldType name="Time" format="4!n" dt:dt="Time" descr="Time in the <FieldType name="LongTime" format="6!n" dt:dt="Time" descr="Time in <FieldType name="BIC/BEI" format="4!a2!a2!c[3!c]" descr="BIC/BEI, a address" /> </FieldTypes> <Tags> <!-- SOURCE FILE: us5mb.pdf. CHAPTER: MT 535: --> <TagInfo name="98A"> <!-- :4!c//8!n (Qualifier)(Date) --> <FieldInfo ref="Qualifier"/> <FieldInfo name="Delimiter" format="/" /> <FieldInfo name="Date" type="LongDate" /> </TagInfo> Page 2 of 12 YYMMDD format" /> the YYYYMMDD format" /> HHMM format" /> the HHMMss format" /> SWIFT registered 681453450 <TagInfo name="94F" descr="Place: Place of Safekeeping"> <!-- :4!c//4!c/4!a2!a2!c[3!c] (Qualifier)(Place)(BIC/BEI) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="Place" format="/4!c" /> <FieldInfo name="Delimiter" format="/" /> <FieldInfo name="BIC/BEI" type="BIC/BEI" /> </TagInfo> <TagInfo name="35B" descr="Identification of the Financial Instrument"> <!-- [ISIN1!e12!c] (Identification of Security) [4*35x] (Description of Security) --> <FieldInfo name="IdentificationOfSecurity" format="[ISIN1!e12!c]" > <FieldInfo name="OneSpace" format="ISIN1!e" /> <FieldInfo name="IdentificationOfSecurity" format="12!c" /> </FieldInfo> <FieldInfo name="DescriptionOfSecurity" format="[4*35x]" startsAtNewLine="true" /> </TagInfo> <TagInfo name="95Q"> <!-- :4!c//4*35x (Qualifier)(Name & Address) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="NameAndAddress" format="/4*35x" /> </TagInfo> </Tags> </SwiftMessageStructure> Примечание: не вся логика этого файла может быть описана средствами XML-схемы. А именно – этими средствами не может быть описана зависимость содержимого одного элемента от значения/наличия другого элемента (т.н. «co-occurrence constraint»). Поэтому, помимо стандартной валидации (выполняемой по XML-схеме), существует ещё и расширенная валидация, выполняемая в коде парсера/композера сразу после десериализации файла-описателя (а также специальной утилитой SwiftMessageStructureValidator.exe). Правила расширенной валидации будут озвучиваться дальше, по ходу изложения. Как видно выше, файл SwiftMessageStructure.xml состоит из 4 основных разделов: <Blocks> - описывает структуру блоков «позиционного» формата, <Fields> - «реестр полей», описывает поля, входящие в состав блоков «позиционного» формата и формата «именованных полей», а также прочие re-usable поля, <FieldTypes> - описывает re-usable типы полей, <Tags> - описывает структуру «тэгов» (из которых состоят блоки «тэгового» формата). Согласно документации SWIFT, структура любого конкретного тэга контекстно-независима, т.е. не привязана к типу сообщения, в которое входит этот тэг. Рассмотрим для примера составление описаний для нескольких тэгов – как наиболее часто встречающуюся задачу. Тэг «28Е». Документация определяет следующий его формат: 5n/4!c - (Page Number)(Continuation Indicator) Т.е. данный тэг состоит из двух обязательных полей, между которыми стоит разделитель. Обязательных – поскольку ни одно из двух полей не заключено в квадратные скобки. Для любого тэга необходимо определить элемент <TagInfo> в разделе <Tags>. И внутри этого элемента – по одному элементу <FieldInfo> на каждое поле, входящее в состав тэга. Уникальность имени тэга (атрибута name элемента <TagInfo>) гарантируется XML-схемой. Элементы <FieldInfo>, расположенные на одном уровне своей иерархии, обязаны иметь уникальные имена (атрибут name) – это гарантируется XML-схемой. Разделители не попадают в SwiftXML-документ. Поэтому тэг 28Е получит описание следующего вида: Page 3 of 12 681453450 <TagInfo name="28E"> <!-- 5n/4!c (Page Number)(Continuation Indicator) --> <FieldInfo name="PageNumber" format="5n" dt:dt="string" /> <FieldInfo name="ContinuationIndicator" format="/4!c" /> </TagInfo> Атрибут dt:dt - когда его значение равно "string" - можно и не указывать. К какому из двух полей отнести разделитель – не имеет значения (в данном случае). С учётом этих двух замечаний, тэг 28Е можно описать и так тоже: <TagInfo name="28E"> <!-- 5n/4!c (Page Number)(Continuation Indicator) --> <FieldInfo name="PageNumber" format="5n/" /> <FieldInfo name="ContinuationIndicator" format="4!c" /> </TagInfo> Кроме того, можно и так: <TagInfo name="28E"> <!-- 5n/4!c (Page Number)(Continuation Indicator) --> <FieldInfo name="PageNumber" format="5n" /> <FieldInfo name="Delimiter" format="/" /> <FieldInfo name="ContinuationIndicator" format="4!c" /> </TagInfo> - т.е. допустимо использовать отдельный элемент <FieldInfo> для описания разделителя; при этом, отдельный элемент <Field> с именем "Delimiter" в SwiftXML-документе создан не будет. Для наглядности можно установить атрибут name равным атрибуту format: <FieldInfo name="/" format="/" /> Итак, описание тэга создано. При разборе парсером dospcc-сообщения, тэг 28Е вида :28E:00001/MORE будет преобразован в следующий фрагмент SwiftXml: <Tag name="28E"> <Field name="PageNumber">00001</Field> <Field name="ContinuationIndicator">MORE</Field> </Tag> Тэг «22F». Документация определяет следующий его формат: :4!c/[8c]/4!c - (Qualifier)(Data Source Scheme)(Indicator) Данный тэг состоит из трёх полей – двух обязательных и одного опционального – между которыми стоят разделители. Описать его можно следующим образом: <TagInfo name="22F"> <!-- :4!c/[8c]/4!c (Qualifier)(Data Source Scheme)(Indicator) --> <FieldInfo name="Qualifier" format=":4!c/" /> <FieldInfo name="DataSourceScheme" format="[8c]" /> <FieldInfo name="Indicator" format="/4!c" /> </TagInfo> Однако, как видно в документации SWIFT, поле Qualifier формата :4!c/ встречается во многих тэгах, поэтому его имеет смысл описать в «реестре полей» - т.е. создать для него отдельный элемент SwiftMessageStructure/Fields/FieldInfo: Page 4 of 12 681453450 <FieldInfo name="Qualifier" format=":4!c/" /> После этого можно сослаться на это re-usable поле посредством атрибута ref: <TagInfo name="22F"> <!-- :4!c/[8c]/4!c (Qualifier)(Data Source Scheme)(Indicator) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="DataSourceScheme" format="[8c]" /> <FieldInfo name="Indicator" format="/4!c" /> </TagInfo> Атрибут ref должен ссылаться на существующий элемент корневого уровня «реестра полей» (т.е. на элемент SwiftMessageStructure/Fields/FieldInfo) - это гарантируется XML-схемой. В корневом уровне «реестра полей» не может быть описателей полей (элементов <FieldInfo>) с заданным атрибутом ref. Если атрибут ref задан, то не может быть следующих атрибутов: name, type, format и dt:dt. Если атрибут ref не задан, то обязан присутствовать атрибут name. Последние 3 правила контролируются процедурой расширенной валидации. Кроме того, опциональность поля DataSourceScheme можно определить не только посредством указания квадратных скобок в формате, но и задав атрибуту isOptional значение true: <TagInfo name="22F"> <!-- :4!c/[8c]/4!c (Qualifier)(Data Source Scheme)(Indicator) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="DataSourceScheme" format="8c" isOptional="true" /> <FieldInfo name="Indicator" format="/4!c" /> </TagInfo> Впрочем, в данном примере всё же нагляднее использовать квадратные скобки: это позволит создать описание поля ровно в том же виде, что указан в документации. Тэг «92А». Документация определяет следующий его формат: :4!c//[N]15d - (Qualifier)(Sign)(Rate) Здесь запись [N] определяет необязательный признак «N», являющийся эквивалентом знака «минус». Описать его можно следующим образом: <TagInfo name="92A"> <!-- :4!c//[N]15d (Qualifier)(Sign)(Rate) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="Delimiter" format="/" /> <FieldInfo name="Sign" format="[1!N]" /> <FieldInfo name="Rate" format="15d" dt:dt="Fixed.14.4" /> </TagInfo> При кодировании необязательного знака необходимо вместо N писать 1!N. Это практически единственное исключение из правила «Как видим формат в SWIFT-документации – так и пишем его в файле-описателе». Однако, поле Sign формата [N] встречается во многих тэгах, поэтому целесообразно вынести его в «реестр полей», создав там вот такую запись: <FieldInfo name="Sign" format="1!N" /> Тогда тэг «92А» можно описать немного по-другому: <TagInfo name="92A"> Page 5 of 12 681453450 <!-- :4!c//[N]15d (Qualifier)(Sign)(Rate) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="Delimiter" format="/" /> <FieldInfo ref="Sign" isOptional="true" /> <FieldInfo name="Rate" format="15d" dt:dt="Fixed.14.4" /> </TagInfo> Также можно было определить в реестре полей поле OptionalSign формата [1!N] (вместо поля Sign формата 1!N), и тогда обойтись в ссылке без атрибута isOptional. Наконец, этот тэг можно описать ещё и так: <TagInfo name="92A"> <!-- :4!c//[N]15d (Qualifier)(Sign)(Rate) --> <FieldInfo name="Qualifier" format=":4!c//" /> <FieldInfo ref="Sign" isOptional="true" /> <FieldInfo name="Rate" format="15d" dt:dt="Fixed.14.4" /> </TagInfo> Какой бы из трёх вариантов описания тэга 92А мы ни выбрали, тэг вида :92A::ABCD//N12345,67 будет преобразован в следующий фрагмент SwiftXml: <Tag name="92A"> <Field name="Qualifier">ABCD</Field> <Field name="Sign">N</Field> <Field name="Rate" dt:dt="Fixed.14.4">12345,67</Field> </Tag> До сих пор мы имели дело с атомарными (простыми) полями. Рассмотрим ситуацию с составными (сложными) полями. Тэг «94F». Документация определяет следующий его формат: :4!c//4!c/4!a2!a2!c[3!c] (Qualifier)(Place)(BIC/BEI) Описать его можно следующим образом: <TagInfo name="94F"> <!-- :4!c//4!c/4!a2!a2!c[3!c] (Qualifier)(Place)(BIC/BEI) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="Place" format="/4!c" /> <FieldInfo name="IdentifierCode" format="/4!a2!a2!c[3!c]" /> </TagInfo> В данном случае, поле IdentifierCode является составным (сложным), т.к. в его состав входит 4 под-поля (3 обязательных и 1 опциональное). Поскольку описание поля IdentifierCode не разложено на описания этих под-полей, парсер не будет разбирать IdentifierCode «на части», а просто ограничится проверкой формата составного поля. К примеру, тэг 94F вида :94F::SAFE//NCSD/CDSLCATT будет преобразован в следующий фрагмент SwiftXml: <Tag name="94F"> <Field name="Qualifier">SAFE</Field> <Field name="Place">NCSD</Field> <Field name="IdentifierCode">CDSLCATT</Field> Page 6 of 12 681453450 </Tag> Однако, есть возможность разложить описание составного поля до вложенных под-полей. Из XMLсхемы видно, что в файле-описателе дозволяется неограниченная вложенность элементов <FieldInfo> друг в друга. Поэтому, если есть необходимость видеть в SwiftXml-документе составные части поля IdentifierCode, тэг 94F можно описать следующим образом: <TagInfo name="94F"> <!-- :4!c//4!c/4!a2!a2!c[3!c] (Qualifier)(Place)(BIC/BEI) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="Place" format="/4!c" /> <FieldInfo name="Delimiter" format="/" /> <FieldInfo name="IdentifierCode" descr="BIC, BEI, or CIVIC"> <FieldInfo name="BankCode" format="4!a" /> <FieldInfo name="CountryCode" format="2!a" /> <FieldInfo name="LocationCode" format="2!c" /> <FieldInfo name="BranchCode" format="[3!c]" /> </FieldInfo> </TagInfo> Необязательно было вводить поле Delimiter - можно было бы просто определить формат поля Place как /4!c/. При таком варианте описания, парсер создаст SwiftXml следующего вида: <Tag name="94F"> <Field name="Qualifier">SAFE</Field> <Field name="Place">NCSD</Field> <Field name="IdentifierCode"> <Field name="BankCode">CDSL</Field> <Field name="CountryCode">CA</Field> <Field name="LocationCode">TT</Field> </Field> </Tag> Обратите внимание, что поле "BranchCode" не будет создано: парсер не создаёт пустые поля! У элемента <FieldInfo>, имеющего вложенные элементы <FieldInfo>, не допускается наличие атрибутов ref, type и dt:dt. У элемента <FieldInfo>, не имеющего вложенных элементов <FieldInfo>, должен присутствовать атрибут format. А у элемента <FieldInfo>, имеющего вложенные элементы <FieldInfo> - этот атрибут может присутствовать, если он необходим для выделения разделителей и/или квадратных скобок. Например, если бы у тэга 94F составное поле IdentifierCode было опциональным, то выделенная выше жёлтым строчка выглядела бы так: <FieldType name="IdentifierCode" format="[4!a2!a2!c[3!c]]"> (хотя можно было бы задействовать уже упоминавшийся ранее атрибут isOptional). У элемента <FieldInfo>, имеющего вложенные элементы <FieldInfo> и в то же время имеющего атрибут format, значение этого атрибута должно быть равно объединённому формату всех вложенных элементов, с возможными квадратными скобками и разделителями по краям. Если бы в нашем примере атрибут format составного поля IdentifierCode выглядел бы как "[8!x[3!c]]", то случилась бы ошибка валидации, т.к. объединённый формат всех дочерних элементов <FieldInfo> (а это не что иное как 4!a2!a2!c[3!c]) не являлся бы подстрокой формата родительского поля (IdentifierCode). Эти три правила контролируются процедурой расширенной валидации. Если требуется, чтобы в SwiftXml попало также и составное значение поля IdentifierCode (в качестве текстового элемента в элементе <Field>), то необходимо задать у поля атрибут Page 7 of 12 681453450 includeRawValueAlways и установить его значение в true. Тогда в документе SwiftXml поле IdentifierCode будет выглядеть следующим образом: <Field name="IdentifierCode"> <Field name="BankCode">CDSL</Field> <Field name="CountryCode">CA</Field> <Field name="LocationCode">TT</Field>CDSLCATT</Field> Того же эффекта можно добиться, установив свойство парсера IncludeRawField в величину WhenToIncludeRawFragment.Always, но тогда текстовый элемент будет создан у всех полей без исключения. Теперь рассмотрим пример с использованием «типов», т.е. элементов SwiftMessageStructure/FieldTypes/FieldType. Возьмём тот же самый тэг – 94F. Определим его по-другому: <TagInfo name="94F"> <!-- :4!c//4!c/4!a2!a2!c[3!c] (Qualifier)(Place)(BIC/BEI) --> <FieldInfo ref="Qualifier" /> <FieldInfo name="Place" format="/4!c" /> <FieldInfo name="Delimiter" format="/" /> <FieldInfo name="IdentifierCode" type="IdentifierCode" /> </TagInfo> - такая запись требует, чтобы был определён «тип» IdentifierCode следующего вида: <FieldType name="IdentifierCode"> <FieldInfo name="BankCode" format="4!a" /> <FieldInfo name="CountryCode" format="2!a" /> <FieldInfo name="LocationCode" format="2!c" /> <FieldInfo name="BranchCode" format="[3!c]" /> </FieldType> Использование «типов» позволяет записи следующего вида: <FieldInfo name="Sender BIC" type="IdentifierCode" /> <FieldInfo name="Receiver BIC" type="IdentifierCode" /> и т.д. Использованием же атрибута ref такого не добиться, поскольку нет возможности изменить имя поля, на которое производится «ссылка» по этому атрибуту. Типы могут быть и простыми – без вложенных элементов <FieldInfo>. Например: <FieldType name="Date" format="6!n" dt:dt="Date" descr="Date in the YYMMDD format" /> <FieldType name="LongDate" format="8!n" dt:dt="Date" descr="Date in the YYYYMMDD format" /> У элементов <FieldInfo>, имеющих атрибут type, не допускается наличие атрибутов format и dt:dt. У элемента <FieldType>, не имеющего вложенных элементов <FieldInfo>, обязан присутствовать атрибут format. Эти два правила контролируются процедурой расширенной валидации. Типы полей определяются в разделе SwiftMessageStructure/FieldTypes. Тэг «35В». Документация определяет следующий его формат: [ISIN1!e12!c] [4*35x] (Identification of Security) (Description of Security) Обратите внимание, что формат двухстрочный! Page 8 of 12 681453450 Описать этот тэг можно следующим образом: <TagInfo name="35B" descr="Identification of the Financial Instrument"> <!-- [ISIN1!e12!c] (Identification of Security) [4*35x] (Description of Security) --> <FieldInfo name="IdentificationOfSecurity" format="[ISIN1!e12!c]" > <FieldInfo name="OneSpace" format="ISIN1!e" /> <FieldInfo name="SecurityID" format="12!c" /> </FieldInfo> <FieldInfo name="DescriptionOfSecurity" format="[4*35x]" startsAtNewLine="true" /> </TagInfo> Формат поля OneSpace демонстрирует, что в качестве разделителя может выступать произвольная комбинация заглавных латинских букв (в данном примере – ISIN), а не только двоеточие или «слэш». Список допустимых разделителей определяется в конфигурационном файле ParserConfig.xml, в элементе ParserConfig/ParseStages/FieldToTypedValues/Delimiters. Атрибут format задан у поля IdentificationOfSecurity только для указания на необязательность этого поля – обратите внимание на квадратные скобки по краям формата. Опциональным является всё составное поле IdentificationOfSecurity целиком, а не каждое из полей OneSpace и SecurityID в отдельности. Впрочем, в данном случае вместо атрибута format можно было бы использовать и атрибут isOptional, с установленным в true значением. Атрибут startsAtNewLine – как и следует из его названия – указывает на то, что перед значением поля, описываемого соответствующим элементом <FieldInfo>, обязан присутствовать перенос строки (символы CRLF). При этом есть один нюанс. Перенос строки является опциональным – но только в том случае, если из двух опциональных строк формата (IdentificationOfSecurity и DescriptionOfSecurity) присутствует только одна; если присутствуют обе, то перенос строки является обязательным. К примеру, тэг 35В вида :35B:ISIN AU000000CFE0 /XX/B1BBJN4 CAPE LAMBERT IRON ORE LIMITED NPV будет преобразован в следующий фрагмент SwiftXml: <Tag name="35B"> <Field name="IdentificationOfSecurity"> <Field name="OneSpace" xml:space="preserve"> </Field> <Field name="IdentificationOfSecurity">AU000000CFE0</Field> </Field> <Field name="DescriptionOfSecurity"> <Line name="1">/XX/B1BBJN4</Line> <Line name="2">CAPE LAMBERT IRON ORE LIMITED</Line> <Line name="3">NPV</Line> </Field> </Tag> Тот же тэг, но вида :35B:ISIN AU000000CFE0 будет преобразован в <Tag name="35B"> <Field name="IdentificationOfSecurity"> <Field name="OneSpace" xml:space="preserve"> </Field> <Field name="IdentificationOfSecurity">AU000000CFE0</Field> </Field> Page 9 of 12 681453450 </Tag> А тэг вида :35B:/XX/B1BBJN4 CAPE LAMBERT IRON ORE LIMITED NPV будет преобразован в <Tag name="35B"> <Field name="DescriptionOfSecurity"> <Line name="1">/XX/B1BBJN4</Line> <Line name="2">CAPE LAMBERT IRON ORE LIMITED</Line> <Line name="3">NPV</Line> </Field> </Tag> Однако, тэг вида :35B:(CRLF) /XX/B1BBJN4 CAPE LAMBERT IRON ORE LIMITED NPV будет признан ошибочным, поскольку поле IdentificationOfSecurity - первое из двух полей, разделённых переносом строки – отсутствует. Типы тэгов. Как видно из документации SWIFT, многие тэги имеют идентичную структуру (формат). Например, тэги 42D, 50D, 51D, 52D, 53D, 54D, 55D, 56D, 57D, 58D, 82D, 83D, 84D, 85D, 86D, 87D, 88D имеют следующий формат: [/1!a][/34x] (Party Identifier) 4*35x (Name and Address) Этот общий для них формат именуется в документации «опцией D» («Option D: Name and Address»). Чтобы не создавать в файле-описателе полтора десятка идентичных описаний вида <TagInfo name="..."> <FieldInfo name="DCMark" format="[/1!a]" /> <FieldInfo name="PartyIdentifier" format="[/34x]" /> <FieldInfo name="NameAddress" format="4*35x" startsAtNewLine="true" /> </TagInfo> можно определить «тип тэга» <TagType name="Party_OptionD" descr="Name and Address"> <!-- [/1!a][/34x] (Party Identifier) 4*35x (Name & Address) --> <FieldInfo name="DCMark" format="[/1!a]" /> <FieldInfo name="PartyIdentifier" format="[/34x]" /> <FieldInfo name="NameAddress" format="4*35x" startsAtNewLine="true" /> </TagType> и уже на него ссылаться из элементов <TagInfo>: <TagInfo name="42D" type="Party_OptionD" /> <TagInfo name="50D" type="Party_OptionD" /> Page 10 of 12 681453450 ... <TagInfo name="88D" type="Party_OptionD" /> Это сделает файл-описатель более компактным и читаемым. Типы тэгов определяются в разделе SwiftMessageStructure/TagTypes. У элементов <TagInfo>, имеющих атрибут type, не допускается наличие вложенных элементов <FieldInfo>. Это правило контролируется процедурой расширенной валидации. Прочие моменты: Парсер, разделив входное dospcc-сообщение на блоки, распознаёт формат каждого блока по правилам, указанным в конфигурационном файле ParserConfig.xml – см. элементы ParserConfig/ParseStages/BlockToFieldsOrTags/BlockFormat/RecognitionRule. Раздел <Blocks> действительно описывает структуру блоков только «позиционного» формата – поскольку без такого описания разделить строку «F21ATILCY2NAXXX0158129890» (к примеру) на поля невозможно. Блоки прочих форматов в подобном описании не нуждаются: у блоков формата «именованных полей» имя поля чётко выделено, и у блоков «тэгового» формата имя тэга тоже чётко выделено. В разделе <Blocks> может быть несколько элементов <Block> с одним и тем же значением атрибута name. В таком случае, имеет место неоднозначность – ведь получается, что блок [«позиционного» формата] с одним и тем же именем может иметь разную структуру. Данная неоднозначность разрешается по принципу «первого удачного парсинга». Например, пусть имеется фрагмент реального файла-описателя: <BlockInfo name="2"> <!--(объединённый формат: 1!a3!n12!c1!a1!n3!n) --> <FieldInfo ref="InputOrOutput" /> <FieldInfo ref="MessageType" /> <FieldInfo ref="ReceiverAddress" /> <FieldInfo ref="MessagePriority" /> <FieldInfo ref="DeliveryMonitoring" /> <FieldInfo ref="ObsolescencePeriod" /> </BlockInfo> <BlockInfo name="2"> <!--(объединённый формат: 1!a3!n4!n28!c6!n4!n1!a) --> <FieldInfo ref="InputOrOutput" /> <FieldInfo ref="MessageType" /> <FieldInfo ref="InputTime" /> <FieldInfo ref="MIR" /> <FieldInfo ref="OutputDate" /> <FieldInfo ref="OutputTime" /> <FieldInfo ref="MessagePriority" /> </BlockInfo> (описание формата каждого отдельного поля для краткости опущено, но в комментариях указан объединённый формат всех полей, составляющих блок) Получив на вход блок с содержимым {2:O9500125090120CHASGB2LEXXX08287999510901200702N} парсер попробует разобрать его в соответствие с 1-м вариантом структуры (1!a3!n12!c1!a1!n3!n), потерпит неудачу, затем попробует 2-й вариант (1!a3!n4!n28!c6!n4!n1!a) - и остановится на нём, Page 11 of 12 681453450 т.к. со 2-м вариантом разбор пройдёт успешно. В этом и заключается «прицип первого удачного парсинга». Если же ни один из вариантов структуры не подойдёт, то парсинг блока «2» завершится с ошибкой. Рассмотрим блок формата «именованных полей» следующего вида: {5:{MAC:00000000}{CHK:9D052EBB2825}{DLM:}} Если мы хотим, чтобы этот блок был успешно разобран парсером, то мы должны обеспечить наличие в файле-описателе следующих элементов <FieldInfo>: <Fields> ... <FieldInfo name="MAC" ... /> <FieldInfo name="CHK" ... /> <FieldInfo name="DLM" ... /> ... </Fields> Обратите внимание, что эти элементы <Fields> должны находиться в корневом уровне «реестра полей»! После внесения любых изменений в файл-описатель, рекомендуется сразу выполнить его расширенную валидацию при помощи утилиты SwiftMessageStructureValidator.exe. Page 12 of 12