Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# XslCompiledTransform和自定义XmlUrlResolver:“;已存在具有相同密钥的条目";_C#_Sql Server_Xml_Xslt_Xslcompiledtransform - Fatal编程技术网

C# XslCompiledTransform和自定义XmlUrlResolver:“;已存在具有相同密钥的条目";

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样式表,在注释出导入时,一切都按预期工作。) 更新:我试图

有没有一种方法可以调试自定义XmlUrlResolver从数据库加载的XSLT文档,或者有人知道下面的errormessage是关于什么的

我有一个XSLT样式表,可以导入一个常见的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
      中也失败

    • 数据库返回的文档中缺少
      头。即使在
      SqlServerDatabaseService
      将控制权返回框架之前手动添加回XML头,错误仍然存在

    事实上,该错误是在.NET Framework代码中的某个地方触发的。这就是我决定下载并安装的原因。(我将解决方案更改为使用该框架的3.5版进行调试。)安装该解决方案并重新启动VS后,您可以在调试会话期间查看并逐步查看框架代码

    从调用
    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", …);