我正在使用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文件?似乎在关闭最后一个节点之后创建了每个节点,在自定义模板上,它只是将每个项目一个接一个地追加。
答案 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
中的设置。