XSLT 无效令牌导致 XML 文档无效
Posted
技术标签:
【中文标题】XSLT 无效令牌导致 XML 文档无效【英文标题】:XSLT invalid token results in invalid XML document 【发布时间】:2019-04-12 05:18:11 【问题描述】:我正在使用 XSLT 文件将 XML 文件转换为另一个 XML 文件,然后在本地创建此 XML 文件。我收到此错误:
System.InvalidOperationException: '处于 Start 状态的令牌文本将导致无效的 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 文件?它似乎在最后一个节点关闭后创建每个节点,并且在自定义模板上它只是一个接一个地附加每个项目。
【问题讨论】:
Transform
方法有一个重载 xslt.Transform(@"D:\Documents\Test2.xml", @"D:\Documents\NewFile.xml")
,所以使用它而不是创建您自己的 XmlWriter,这样 XslCompiledTransform 将在内部使用您的 xsl:output
中的正确设置创建一个。您收到的消息表明您的 XSLT 创建了一个包含多个***元素的片段,如果您想使用自己的 XmlWriter 来获得这样的结果,您需要使用正确的 XmlWriterSettings 和 ConformanceLevel.Fragment
。
谢谢@MartinHonnen。出于某种原因,将转换切换到您建议的重载转换甚至在不更改 XmlWriterSettings 的情况下摆脱了我的片段错误。甚至应该以这种方式发生吗?它生成的文件看起来也正确。
【参考方案1】:
这是一个非常无用的信息,不是吗?但我想我可以为你破译。
XSLT 处理器通过将诸如开始文档、开始元素、输出文本等事件写入 XML Writer 来生成其输出。
如果您想生成一个格式良好的 XML 文档,那么您不能在第一个元素的开始之前有任何文本。该消息是说,如果您做的最后一件事是发出 start-document,那么接下来的事情不允许是文本,因为该文档格式不正确(它说无效,但它意味着格式不正确) .
现在,XSLT 样式表被允许生成“格式良好的片段”,而不仅仅是被允许编写“格式良好的文档”。实际上,XML规范中使用的术语是“格式良好的外部通用解析实体”,但这有点拗口,所以每个人都称它们为“片段”,因为这就是DOM所说的,并且没有使用正确的术语在如果没有人理解错误消息。不同之处在于,一个片段可以在顶层包含多个元素和文本节点,例如this <b>really</b> is a <i>well-formed</i> fragment
。问题是您将 XSLT 输出写入到的目的地可能无法处理片段,在这种特殊情况下,XML 编写器只有在配置为这样做时才能处理片段。
我怀疑您实际上并不打算生成片段,并且您需要修复您的 XSLT 代码,以便它输出格式正确的文档。
【讨论】:
【参考方案2】:为了扩展 Michael Kay 的出色答案(因为这在 cmets 中写得太长了),对于您的特定输入 XML,问题在于空格。在匹配/In
的模板中,你这样做...
<xsl:template match="/In">
<!-- Remove the 'In' element -->
<xsl:apply-templates select="node()"/>
</xsl:template>
但是通过选择node()
,您将选择子Submit
之前和之后的空白节点,因此您最终会在导致错误的根Q
元素之前得到一个文本节点。
因此,在这种情况下,您可以做的就是通过将其添加到您的 XSLT 中,从 XML 中去除空格
<xsl:strip-space elements="*" />
或者,您也可以这样做,仅选择元素,而不是其他节点(尽管这会省略 cmets 和处理指令)
<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
中的设置。
【讨论】:
据我所知,只有一个提交元素。如果不是这种情况,那么 XSLT 将不得不更改对吗? 是的。如果有多个submit
元素,并且您想输出格式正确的 XML(而不是片段),则必须输出一个包含所有子 Q
元素的新根元素。
小细节:XML 允许格式良好的文档在最外层元素节点之前和之后包含空白字符。但从这个证据看来,微软的 XMLWriter 不允许这样做。以上是关于XSLT 无效令牌导致 XML 文档无效的主要内容,如果未能解决你的问题,请参考以下文章
包含 ∈ 的 XML 文档无效 - 如何使用 XSLT 输出?
使用 Firebase 登录 Facebook 导致无效 OAuth 访问令牌错误