XSLT无效令牌导致无效XML文档

时间:2018-11-08 16:34:08

标签: c# .net xml xslt

我正在使用XSLT文件将XML文件转换为另一个XML文件,然后在本地创建此XML文件。我收到此错误:

  

System.InvalidOperationException:'处于开始状态的令牌文本将导致无效的XML文档。如果要编写XML片段,请确保将ConformanceLevel设置设置为ConformanceLevel.Fragment或ConformanceLevel.Auto。 '

XSLT文件已在Visual Studio中调试,看起来好像可以正常工作,但我不理解此错误。这是什么意思,如何解决?

这是我的XML:

<?xml version="1.0" encoding="utf-8"?>
<In xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="take.xsd">
  <Submit ID="1234">
    <Values>
      <Code>34</Code>
      <Source>27</Source>
    </Values>
    <Information>
      <Number>55</Number>
      <Date>2018-05-20</Date>
      <IsFile>1</IsFile>
      <Location></Location>
      <Files>
        <File>
          <Name>Red.pdf</Name>
          <Type>COLOR</Type>
        </File>
        <File>
          <Name>picture.pdf</Name>
          <Type>IMAGE</Type>
        </File>        
      </Files>
    </Information>
  </Submit>
</In>

我的XSLT代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

  <!-- identity template - copies all elements and its children and attributes -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/In">
    <!-- Remove the 'In' element -->
    <xsl:apply-templates select="node()"/>
  </xsl:template>

  <xsl:template match="Submit">
    <!-- Create the 'Q' element and its sub-elements -->
    <Q xmlns:tns="Q" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schema.xsd" Source="{Values/Source}" Notification="true">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="Values" />
        <xsl:apply-templates select="Information" />
        <xsl:apply-templates select="Information/Files" />
      </xsl:copy>
    </Q>
  </xsl:template>

  <xsl:template match="Information">
    <!-- Create the 'Data' sub-element without all of its children -->
    <xsl:copy>
      <xsl:copy-of select="Number"/>
      <xsl:copy-of select="Date"/>
      <xsl:copy-of select="IsFile"/>
      <xsl:copy-of select="Location"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

这是用于转换文件的C#代码:

        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load(@"D:\\Main\XLSTFiles\Test.xslt");
        string xmlPath = @"D:\Documents\Test2.xml";
        using (XmlWriter w = XmlWriter.Create(@"D:\Documents\NewFile.xml"))
        {
            xslt.Transform(xmlPath, w);
        }

还有没有办法生成带有适当缩进的新XML文件?似乎在关闭最后一个节点之后创建了每个节点,在自定义模板上,它只是将每个项目一个接一个地追加。

2 个答案:

答案 0 :(得分:2)

这是一条非常无用的信息,不是吗?但是我想我可以为您解密。

XSLT处理器通过将事件(例如开始文档,开始元素,输出文本)写入XML Writer来产生其输出。

如果要生成格式正确的XML文档,则在第一个元素开始之前不能有任何文本。消息是说,如果您做的最后一件事是颁发起始文档,则不允许将下一个内容输入文本,因为文档格式不正确(它表示无效,但表示格式不正确)

现在,允许XSLT样式表产生“格式正确的片段”,而不是仅允许编写“格式正确的文档”。实际上,XML规范中使用的术语是“格式良好的外部通用解析实体”,但这有点大话,所以每个人都称它们为“碎片”,因为那是DOM所称的,在正确的术语中没有意义。错误消息(如果没人能理解)。区别在于片段可以在顶层包含多个元素和文本节点,例如this <b>really</b> is a <i>well-formed</i> fragment。问题在于,您将XSLT输出写入的目标可能无法处理片段,在这种情况下,XML Writer仅在配置为可以处理片段的情况下才可以处理片段。

我怀疑您实际上并不打算生成片段,您需要修复XSLT代码,以便它输出格式正确的文档。

答案 1 :(得分:2)

为了扩展Michael Kay的出色答案(因为这太长了,无法在注释中写),对于您的特定输入XML,问题出在空白。在与/In匹配的模板中,您可以执行此操作...

<xsl:template match="/In">
  <!-- Remove the 'In' element -->
  <xsl:apply-templates select="node()"/>
</xsl:template>

但是,通过选择node(),您将选择子节点Submit之前和之后的空白节点,因此最终会在根Q元素之前导致文本节点,从而导致错误。 / p>

因此,在这种情况下,您可以做的就是将XML添加到XSLT中,从而简单地从XML中去除空格

<xsl:strip-space elements="*" />

或者,您也可以这样做,只选择元素,而不选择其他节点(尽管这会省略注释和处理指令)

<xsl:apply-templates select="*" />

但是,如果XML中有多个Submit元素,则输出中将有多个Q元素,这将是一个片段,因为只有一个根元素。如果这是您的真正意图,则应对C#进行以下更改...

 using (XmlWriter w = XmlWriter.Create(@"C:\Users\tcase.BGT\Documents\NewFile.xml", xslt.OutputSettings ))

默认ConformanceLevel是ConformanceLevel.Auto,我认为它允许片段。添加此选项还将解决您的缩进问题,因为它将使用xsl:output中的设置。