Вывод XSLT 1.0 Hex 0x1C - 0x1F в текстовый файл

Я использую xslt версии 1.0 для преобразования файла XML в текстовый файл, который отправляется третьей стороне. Сторонний формат требует, чтобы поля данных были разделены с помощью 0x1F (разделитель единиц ascii), группы должны быть разделены с помощью 0x1D (разделитель групп ascii), а записи - 0x1E (разделитель записей ascii). Использование их в таблице стилей приводит к ошибке ниже.

Символ ' ', шестнадцатеричное значение 0x1D недопустимо в документах XML.

В настоящее время я использую от 0x80 до 0x82 из расширенного набора символов, затем запускаю результат преобразования через функцию замены в C#, чтобы заменить значения, которые я использовал, теми, которые мне действительно нужны, но, похоже, должен быть лучший, более эффективный способ сделать это.

Есть ли способ вывести эти значения в текстовый файл, используя таблицу стилей напрямую?

Текущая таблица стилей

<?xml version="1.0" encoding="us-ascii"?>

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:asap="http://www.asapnet.org/pmp/4.2/exchange"
                xmlns:asap-code="http://www.asapnet.org/pmp/4.2/extension/code"
                xmlns:asap-ext="http://www.asapnet.org/pmp/4.2/extension"
                xmlns:asap-meta="http://www.asapnet.org/pmp/4.2/extension/meta"
                xmlns:nc="http://release.niem.gov/niem/niem-core/3.0/"
                exclude-result-prefixes="asap asap-code asap-ext asap-meta nc">

  <xsl:output method="text" omit-xml-declaration="yes" indent="no" />

  <xsl:variable name="FieldSeparator" select="'&#127;'"/>
  <xsl:variable name="SegmentTerminator" select="'&#128;'"/>


  <!--MAIN-->
  <xsl:template match="asap:ReportTransmission">
    <xsl:apply-templates select="asap-meta:TransactionHeader"/>
    <xsl:apply-templates select="asap-meta:InformationSource"/>
    <xsl:apply-templates select="asap-ext:ReportingPharmacy"/>
  </xsl:template>


  <!--TRANSACTION HEADER - TH SEGMENT-->
  <xsl:template match="asap-meta:TransactionHeader">
    <xsl:value-of select="concat(
                  'TH',
                  $FieldSeparator,
                  asap-meta:ReleaseNumberText,
                  $FieldSeparator,
                  asap-meta:ControlNumberText,
                  $FieldSeparator,
                  asap-code:TransactionKindCode,
                  $FieldSeparator,
                  concat(substring(asap-meta:TransactionDate,1,4),substring(asap-meta:TransactionDate,6,2),substring(asap-meta:TransactionDate,9,2)),
                  $FieldSeparator,
                  concat(substring(asap-meta:TransactionTime,1,2),substring(asap-meta:TransactionTime,4,2)),
                  $FieldSeparator,
                  asap-code:FileKindCode,
                  $FieldSeparator,
                  asap-meta:RoutingNumber,
                  $FieldSeparator,
                  $SegmentTerminator,
                  $SegmentTerminator)" />
  </xsl:template>


  <!--INFORMATION SOURCE - IS SEGMENT-->
  <xsl:template match="asap-meta:InformationSource">
        <xsl:value-of select="concat(
                  'IS',
                  $FieldSeparator,
                  nc:Identification/nc:IdentificationID,
                  $FieldSeparator,
                  nc:Identification/nc:IdentificationJurisdiction/nc:JurisdictionText,
                  $FieldSeparator,
                  nc:MessageText,
                  $SegmentTerminator)" />

  </xsl:template>
</xsl:stylesheet>

(... таблица стилей продолжается с дополнительными сегментами...)

Токовый выход (Блокнот ++)

(... вывод продолжается с дополнительными сегментами...)

Пример XML

<?xml version="1.0" encoding="UTF-8"?>
<asap:ReportTransmission xmlns:asap="http://www.asapnet.org/pmp/4.2/exchange"
 xmlns:asap-code="http://www.asapnet.org/pmp/4.2/extension/code"
 xmlns:asap-ext="http://www.asapnet.org/pmp/4.2/extension"
 xmlns:asap-meta="http://www.asapnet.org/pmp/4.2/extension/meta"
 xmlns:nc="http://release.niem.gov/niem/niem-core/3.0/" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.asapnet.org/pmp/4.2/exchange ../schemas/exchange/pmp_exchange.xsd">
    <asap-meta:TransactionHeader>
        <asap-meta:ReleaseNumberText>4.2</asap-meta:ReleaseNumberText>
        <asap-meta:ControlNumberText>857463</asap-meta:ControlNumberText>
        <asap-code:TransactionKindCode>01</asap-code:TransactionKindCode>
        <asap-meta:TransactionDate>2009-10-15</asap-meta:TransactionDate>
        <asap-meta:TransactionTime>10:45:00</asap-meta:TransactionTime>
        <asap-code:FileKindCode>P</asap-code:FileKindCode>
    </asap-meta:TransactionHeader>
    <asap-meta:InformationSource>
        <nc:Identification>
            <nc:IdentificationID>7564</nc:IdentificationID>
            <nc:IdentificationJurisdiction>
                <nc:JurisdictionText>ACME PHARMACY</nc:JurisdictionText>
            </nc:IdentificationJurisdiction>
        </nc:Identification>
    </asap-meta:InformationSource>
    <asap-ext:ReportingPharmacy>
        <asap-ext:NPIIdentification>
            <nc:IdentificationID>1234567890</nc:IdentificationID>
        </asap-ext:NPIIdentification>
        <asap-ext:PatientInfo>
            <nc:PersonBirthDate>
                <nc:Date>1950-01-01</nc:Date>
            </nc:PersonBirthDate>
            <nc:PersonName>
                <nc:PersonGivenName>John</nc:PersonGivenName>
                <nc:PersonSurName>Smith</nc:PersonSurName>
            </nc:PersonName>
            <nc:PersonSexText>Male</nc:PersonSexText>
            <asap-ext:PrimaryIdentification>
                <nc:PersonLicenseIdentification>
                    <nc:IdentificationID>987544</nc:IdentificationID>
                    <nc:IdentificationJurisdiction>
                        <nc:LocationStateUSPostalServiceCode>MA</nc:LocationStateUSPostalServiceCode>
                    </nc:IdentificationJurisdiction>
                </nc:PersonLicenseIdentification>
            </asap-ext:PrimaryIdentification>
            <nc:ContactMailingAddress>
                <nc:LocationStreet>
                    <nc:StreetName>1234 Main St</nc:StreetName>
                </nc:LocationStreet>
                <nc:LocationCityName>Somewhere</nc:LocationCityName>
                <nc:LocationStateUSPostalServiceCode>MA</nc:LocationStateUSPostalServiceCode>
                <nc:LocationPostalCode>54356</nc:LocationPostalCode>
            </nc:ContactMailingAddress>
            <asap-ext:DispensingRecord>
                <asap-code:ReportingStatusCode>00</asap-code:ReportingStatusCode>
                <asap-ext:Prescription>
                    <asap-ext:PrescriptionNumberText>6542984</asap-ext:PrescriptionNumberText>
                    <asap-ext:PrescriptionWrittenDate>
                        <nc:Date>2009-10-15</nc:Date>
                    </asap-ext:PrescriptionWrittenDate>
                    <asap-ext:PrescriptionRefillQuantity>0</asap-ext:PrescriptionRefillQuantity>
                    <asap-ext:ProductIdentification>
                        <nc:IdentificationID>57866707401</nc:IdentificationID>
                        <asap-code:ProductIdentifierKindCode>01</asap-code:ProductIdentifierKindCode>
                    </asap-ext:ProductIdentification>
                    <asap-ext:PrescriptionSupplyQuantity>15</asap-ext:PrescriptionSupplyQuantity>
                </asap-ext:Prescription>
                <asap-ext:Transaction>
                    <asap-ext:PrescriptionFilledDate>
                        <nc:Date>2009-10-15</nc:Date>
                    </asap-ext:PrescriptionFilledDate>
                    <asap-ext:PrescriptionRefillNumber>0</asap-ext:PrescriptionRefillNumber>
                    <asap-ext:PrescriptionDispensedQuantity>30</asap-ext:PrescriptionDispensedQuantity>
                </asap-ext:Transaction>
                <asap-ext:Prescriber>
                    <asap-ext:DEAIdentification>
                        <nc:IdentificationID>AW8765432</nc:IdentificationID>
                    </asap-ext:DEAIdentification>
                </asap-ext:Prescriber>          
                <asap-ext:AdditionalInformation>
                    <asap-ext:IssuingPrescriptionBlankIdentification>
                        <nc:IdentificationID>787456493993</nc:IdentificationID>
                        <nc:IdentificationJurisdiction>
                            <nc:LocationStateUSPostalServiceCode>MA</nc:LocationStateUSPostalServiceCode>
                        </nc:IdentificationJurisdiction>
                    </asap-ext:IssuingPrescriptionBlankIdentification>
                </asap-ext:AdditionalInformation>
            </asap-ext:DispensingRecord>
        </asap-ext:PatientInfo>
    </asap-ext:ReportingPharmacy>
</asap:ReportTransmission>

Обновить


Для тех, кто может искать подобное решение, я остановился на скрипте C# в таблице стилей.

  <msxsl:script implements-prefix="CSharpScripts" language="C#">
    public string FS()
    {
    return '\u001F'.ToString();
    }

    public string GS()
    {
    return '\u001D'.ToString();
    }
  </msxsl:script>

Затем его можно использовать так:

<xsl:value-of select="CSharpScripts:FS()"/>

Вам нужно установить EnableScript = true с помощью XsltSettings при загрузке XslCompiledTransform и установить CheckCharacters = false на XmlWriter, используемом для вывода:

            var xslt = new XslCompiledTransform();
            xslt.Load(
                    @"E:\TFS\Transforms\TestTransform.xslt",
                    new XsltSettings() {EnableScript = true}, null);

            var writerSettings = xslt.OutputSettings.Clone();
            writerSettings.CheckCharacters = false;

            var sb = new StringBuilder();

            var xmlOutput = XmlWriter.Create(sb, writerSettings);

            xslt.Transform(@"E:\samples.xml", xmlOutput);

Спасибо @Abel за то, что указал мне правильное направление.

1 ответ

Решение

Вы, похоже, один из немногих, у кого есть разумное требование для использования XML 1.1. Действительно, как вы выяснили, в XML 1.0 невозможно использовать управляющие символы ниже 0x20, кроме tab, cr и lf. Поскольку XSLT написан на XML, это означает, что вам не понадобится процессор, который может читать документ экземпляра XSLT из XML 1.1.

Насколько я знаю, существует только один процессор XSLT 1.0, способный обрабатывать XML 1.1, и это Saxon 6.5 (или более поздняя версия Saxon, но тогда вы могли бы также перейти к использованию XSLT 2.0 или 3.0). Порт IKVM для.NET Saxon существует и поддерживается (и нет, я не аффилирован, на самом деле я написал Exselt, но у нас пока нет планов по поддержке XML 1.1).

Вам не нужно изменять входные данные в XML 1.1, только таблицу стилей, потому что именно здесь вам нужно использовать эти символы.

В надлежащем редакторе XML, который способен работать с XML 1.1, измените следующее:

<?xml version="1.0" encoding="UTF-8"?>

в

<?xml version="1.1" encoding="UTF-8"?>

Затем измените ваши разделители, чтобы использовать символы, которые вы хотите их использовать:

<xsl:variable name="FieldSeparator" select="'&#x1F;'" />
<xsl:variable name="SegmentTerminator" select="'&#x1D;'" />

Затем ошибка должна исчезнуть (если у вас все еще есть ошибка, вы не используете процессор, способный работать с XML 1.1, т. Е. В.NET вы застряли с XML 1.0, и у Microsoft нет планов по обновлению как "использование"). в дикой природе "XML 1.1 очень, очень маленький).

Другие альтернативы:

  • Используйте функцию расширения, которая может написать закодированный символ. В.NET это довольно тривиально, однако я не знаю, будет ли возвращение управляющего символа ASCII писателем XML.
  • Используйте новый двоичный модуль EXPath, но он довольно новый, и я не уверен, что такое поддержка уровня op. Тем не менее, он работает с любой версией XML или XSLT
  • Постобработка вашего вывода (как вы делаете сейчас). Лучше всего использовать символ Unicode Private Use, так как шансы на столкновения практически ничтожны.
  • (Вы можете испытать желание использовать xsl:character-maps или же codepoints-to-string() с XSLT 2.0, но вы столкнетесь с той же проблемой, только на более позднем этапе.)

PS: настройка omit-xml-declaration="yes" а также indent="no" избыточны, текстовый вывод никогда не будет иметь декларации xml и не обеспечит авто-отступ.

PPS: предоставленный вами пример XSLT сбрасывает много текста в местах, которые не соответствуют вашему описанию. Добавление шаблона с мелким пропуском решает его, но выводит только одну строку. Я не проверял, так ли это, как задумано.

Другие вопросы по тегам