C# XslCompiledTransform和自定义XmlUrlResolver:“;已存在具有相同密钥的条目";
有没有一种方法可以调试自定义XmlUrlResolver从数据库加载的XSLT文档,或者有人知道下面的errormessage是关于什么的 我有一个XSLT样式表,可以导入一个常见的XSLT文档:C# XslCompiledTransform和自定义XmlUrlResolver:“;已存在具有相同密钥的条目";,c#,sql-server,xml,xslt,xslcompiledtransform,C#,Sql Server,Xml,Xslt,Xslcompiledtransform,有没有一种方法可以调试自定义XmlUrlResolver从数据库加载的XSLT文档,或者有人知道下面的errormessage是关于什么的 我有一个XSLT样式表,可以导入一个常见的XSLT文档: <xsl:import href="db://common.hist.org"/> 更新:以下基本上是请求的解析器代码,但我的代码中没有发生异常;因此,我猜下面的代码中没有明显的原因。(这段代码实际上用于加载包含导入的XSLT样式表,在注释出导入时,一切都按预期工作。) 更新:我试图
<xsl:import href="db://common.hist.org"/>
更新:以下基本上是请求的解析器代码,但我的代码中没有发生异常;因此,我猜下面的代码中没有明显的原因。(这段代码实际上用于加载包含导入的XSLT样式表,在注释出导入时,一切都按预期工作。)
更新:我试图通过临时从web服务器加载样式表来隔离问题,这是可行的。我了解到,与存储在Web服务器上的样式表不同,SQL Server显然只存储XML片段而不存储XML声明 更新:异常的堆栈跟踪: System.Xml.Xsl.xsloadexception:XSLT Kompilierungsfehler。贝菲勒(91616)。——>System.ArgumentException:已存在具有相同密钥的条目。。bei System.Collections.Specialized.ListDictionary.Add(对象键,对象值)bei System.Collections.Specialized.HybridDictionary.Add(对象键,对象值)bei System.Xml.Xsl.Xslt.Xslt.Xslt.XsltLoader.XsltLoader.LoadStylesheet(XmlReader reader,Boolean include)bei System.Xml.Xsl.Xsl.Xslt.XsltLoader.LoadStylesheet(Uri Uri,Boolean include)bei System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader,Boolean include)---Ende der inner ablaufferforgung des ausnamestacks---bei System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader,Boolean include)bei System.Xml.Xsl.Xslt.XsltLoader.Load(XmlReader reader)bei System.Xml.Xsl.Load(编译器编译器,对象样式表,XmlResolver XmlResolver)bei System.Xml.Xsl.Xsl.Compiler.Compile(对象样式表,XmlResolver XmlResolver,qil表达式和qil)bei System.Xml.Xsl.Xsl.xslciledTransform.LoadInternal(对象样式表,XsltSettings设置,XmlResolver样式表解析器)bei System.Xml.Xsl.xslciledTransform.Load(字符串样式表URI、XsltSettings设置、XmlResolver样式表Resolver)bei(我的命名空间和类)。GetXslTransform(布尔预转换)bei(我的命名空间和类)。get_XslHtmlOutput()bei(我的命名空间和类)。get_DisplayMarkup() 简短答复: 您的
IDatabaseService
接口方法返回XmlReader
对象。构造这些对象时,请确保将baseUri
传递给构造函数;例如:
public XmlReader GetApplicationXslt(string applicationName)
{
…
var baseUri = string.Format("db://{0}.hist.org", applicationName);
return XmlReader.Create(input: …,
settings: …,
baseUri: baseUri); // <-- this one is important!
}
IDatabaseService.cs: 此文件包含
IDatabaseService
接口的定义,这里不再重复
SqlServerDatabaseService.cs: 它包含一个实现
IDatabaseService
的类。它将数据读取/写入上述数据库:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Xml;
class SqlServerDatabaseService : IDatabaseService
{
// creates a connection based on connection string from App.config:
SqlConnection CreateConnection()
{
return new SqlConnection(connectionString: ConfigurationManager.ConnectionStrings["SqlServerDatabase"].ConnectionString);
}
// stores an XML document into the 'ApplicationDocuments' table:
public void StoreApplicationDocument(string applicationName, XmlReader document)
{
using (var connection = CreateConnection())
{
SqlCommand command = connection.CreateCommand();
command.CommandText = "INSERT INTO ApplicationDocuments (ApplicationName, Document) VALUES (@applicationName, @document)";
command.Parameters.Add(new SqlParameter("@applicationName", applicationName));
command.Parameters.Add(new SqlParameter("@document", new SqlXml(document)));
// ^^^^^^^^^^^^^^^^^^^^
connection.Open();
int numberOfRowsInserted = command.ExecuteNonQuery();
connection.Close();
}
}
// reads an XML document from the 'ApplicationDocuments' table:
public XmlReader GetApplicationXslt(string applicationName)
{
using (var connection = CreateConnection())
{
SqlCommand command = connection.CreateCommand();
command.CommandText = "SELECT Document FROM ApplicationDocuments WHERE ApplicationName = @applicationName";
command.Parameters.Add(new SqlParameter("@applicationName", applicationName));
connection.Open();
var plainXml = (string)command.ExecuteScalar();
connection.Close();
if (plainXml != null)
{
return XmlReader.Create(new StringReader(plainXml));
}
else
{
throw new KeyNotFoundException(message: string.Format("Database does not contain a application document named '{0}'.", applicationName));
}
}
}
… // (all other methods throw a NotImplementedException)
}
xmldbsolver.cs: 这包含
xmldbsolver
类,它与您的xmldbsolver
类相同,只是有两个更改:
IDatabaseService
对象。此对象用于代替DatabaseServiceFactory.DatabaseService
Tracing.TraceHelper.WriteLine的调用
CommonHistOrg.xslt: 这是
db://common.hist.org
样式表,将在运行时放入数据库(请参见下面的Program.cs
):
TestStylesheet.xml: 这是一个引用上述
db://common.hist.org
样式表的样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="db://common.hist.org"/>
</xsl:stylesheet>
Program.cs: 其中包含测试应用程序代码:
using System;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
class Program
{
static void Main(string[] args)
{
var databaseService = new SqlServerDatabaseService();
// put CommonHistOrg.xslt into the 'ApplicationDocuments' database table:
databaseService.StoreApplicationDocument(
applicationName: "common",
document: XmlReader.Create("CommonHistOrg.xslt"));
// load the XSLT stylesheet:
var xslt = new XslCompiledTransform();
xslt.Load(@"TestStylesheet.xslt",
settings: XsltSettings.Default,
stylesheetResolver: new XmlDbResolver(databaseService));
// load the XML test input:
var input = XmlReader.Create("TestInput.xml");
// transform the test input and store the result in 'output':
var output = new StringBuilder();
xslt.Transform(input, XmlWriter.Create(output));
// display the transformed output:
Console.WriteLine(output.ToString());
Console.ReadLine();
}
}
在我的机器上工作起来很有魅力:输出是一个带有空根元素的XML文档
,这就是db://common.hist.org
样式表从测试输入中为匹配的
元素输出的内容
更新:错误复制和修复:
Main
方法中插入以下语句:
databaseService.StoreApplicationDocument(
applicationName: "test",
document: XmlReader.Create("TestStylesheet.xslt"));
xslt.Load(@"TestStylesheet.xslt", …);
做
这将触发OP报告的错误- 数据库表中的
列的类型为Document
。它在XML
中也失败NTEXT
- 数据库返回的文档中缺少
头。即使在
将控制权返回框架之前手动添加回XML头,错误仍然存在SqlServerDatabaseService
xslt.Load(…;)开始
在我们的Main
方法中,我进入了框架代码,最终在XsltLoader.cs
中找到了一个方法LoadStylesheet
。有一个名为documentUrisInUse
的混合字典,它显然存储了已加载样式表的基本URI。因此,如果我们加载多个样式表如果eet的基URI为空或缺失,此方法将尝试向该字典添加两次null
;这就是导致错误的原因
因此,一旦您为IDatabaseService
返回的每个样式表分配了唯一的基URI,一切都会正常工作。您可以通过将baseUri
传递给XmlReader
构造函数来实现这一点。请参阅我答案开头的代码示例。您还可以通过复制或克隆来检索更新的工作解决方案(git clone https://g
<?xml version="1.0" encoding="utf-8" ?>
<Foo/>
using System;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
class Program
{
static void Main(string[] args)
{
var databaseService = new SqlServerDatabaseService();
// put CommonHistOrg.xslt into the 'ApplicationDocuments' database table:
databaseService.StoreApplicationDocument(
applicationName: "common",
document: XmlReader.Create("CommonHistOrg.xslt"));
// load the XSLT stylesheet:
var xslt = new XslCompiledTransform();
xslt.Load(@"TestStylesheet.xslt",
settings: XsltSettings.Default,
stylesheetResolver: new XmlDbResolver(databaseService));
// load the XML test input:
var input = XmlReader.Create("TestInput.xml");
// transform the test input and store the result in 'output':
var output = new StringBuilder();
xslt.Transform(input, XmlWriter.Create(output));
// display the transformed output:
Console.WriteLine(output.ToString());
Console.ReadLine();
}
}
databaseService.StoreApplicationDocument(
applicationName: "test",
document: XmlReader.Create("TestStylesheet.xslt"));
xslt.Load(@"TestStylesheet.xslt", …);
xslt.Load(@"db://test.hist.org", …);