【问题标题】:XSLT 1.0 Output Hex 0x1C - 0x1F to Text FileXSLT 1.0 将十六进制 0x1C - 0x1F 输出到文本文件
【发布时间】:2016-01-10 10:10:18
【问题描述】:

我正在使用 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()"/>

您确实需要在加载 XslCompiledTransform 时使用 XsltSettings 设置 EnableScript = true,并设置 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 为我指明了正确的方向。

【问题讨论】:

  • 您的输出方法是否设置为“文本”?您究竟是如何“使用”样式表中的字符的?事实上,为什么不发布一个完整且可重现的 XML + XSLT 示例?
  • 更新问题。是的,我使用输出作为“文本”。这些字符在文本文件中用作字段、组和段分隔符。
  • 你到底在哪里得到这个错误?在加载 xsl 时,还是在您尝试进行转换时?
  • @Flynn1179,该字符在 XSLT 内部,即 XML,这意味着它不能使用该字符,因为它在 XML 中是被禁止的。不可能编写使用禁止的 XML 字符的 XSLT,因为 XML 甚至不会解析,因此,它一开始就永远不会到达 XSLT 处理器。
  • 我刚刚添加了XML 1.1 tag:您是 7 年来第 20 个提出适合 XML 1.1 类别的问题的人!

标签: c# xml xslt xslt-1.0 xml-1.1


【解决方案1】:

您似乎是少数对使用 XML 1.1 有合理要求的人之一。事实上,正如您所发现的,在 XML 1.0 中,除了制表符、cr 和 lf 之外,不可能使用低于 0x20 的控制字符。由于 XSLT 是用 XML 编写的,这意味着您不需要可以从 XML 1.1 读取 XSLT 实例文档的处理器。

据我所知,只有一个 XSLT 1.0 处理器能够处理 XML 1.1,那就是 Saxon 6.5(或 Saxon 的更高版本,但您也可以直接跳到使用 XSLT 2.0 或 3.0)。 Saxon 的 .NET 的 IKVM 端口存在且受支持(不,我隶属于,事实上,我编写了 Exselt,但我们还没有计划支持 XML 1.1)。

您无需将输入更改为 XML 1.1,只需将样式表更改为样式表,因为您需要在此处使用这些字符。

在能够处理 XML 1.1 的适当 XML 编辑器中,更改以下内容:

<?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 中,这很简单,但是,我不知道 XML 编写器是否会接受返回 ASCII 控制字符。
  • 使用新的EXPath binary module,但它很新,我不确定级别操作支持是什么。但是,它适用于任何 XML 或 XSLT 版本
  • 后处理您的输出(就像您现在所做的那样)。最好使用Unicode Private Use character,因为这样发生碰撞的机会几乎为零。
  • (您可能很想将xsl:character-mapscodepoints-to-string() 与XSLT 2.0 一起使用,但您会在稍后阶段遇到同样的问题。)

PS:设置omit-xml-declaration="yes"indent="no"是多余的,文本输出永远不会有xml声明,也不会提供自动缩进。

PPS:您提供的示例 XSLT 在不符合您描述的地方转储了大量文本。添加一个浅跳过模板可以解决它,但只输出一行。我没有检查这是否符合预期。

【讨论】:

  • +1 提醒我们有关 XML 1.1 的信息。 “据我所知,只有一个 XSLT 1.0 处理器能够处理 XML 1.1,那就是 Saxon 6.5” Xalan 也支持它。
  • 非常感谢您的回答和提示。我正在使用 VS 2012,可能会坚持使用 1.0,但我会研究 Saxon 和 Xalan 作为替代方案。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-18
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 2013-07-07
  • 1970-01-01
相关资源
最近更新 更多