XslCompiledTransform 和自定义 XmlUrlResolver:“具有相同键的条目已存在”

2024-05-03

有没有办法调试由自定义 XmlUrlResolver 从数据库加载的 XSLT 文档,或者有人知道下面的错误消息是关于什么的吗?

我有一个导入通用 xslt 文档的 XSLT 样式表:

<xsl:import href="db://common.hist.org"/>

该计划由海关处理XmlResolver http://msdn.microsoft.com/en-us/library/system.xml.xmlresolver.aspx从数据库加载 XSLT 文档,但我收到错误:

具有相同密钥的条目已存在。

引用的通用 XSLT 文档xsl:import包含一些常见的 XSLT 模板,每个模板都有唯一的名称。

将 XSLT 文档从本地文件系统移动到数据库后,开始出现此错误。当使用指向本地文件的默认导入方案以及从本地文件系统加载 XSLT 文档时,不会发生错误。

我还尝试在创建实例时打开调试XslCompiledTransform,但不知何故不可能“步入”基于数据库的 XSLT。

_xslHtmlOutput = new XslCompiledTransform(XSLT_DEBUG);

Update:以下基本上是请求的解析器​​代码,但异常没有发生在我的代码中;因此我猜下面的代码中没有明显的原因。 (这个相同的代码实际上用于加载包含导入的 XSLT 样式表,并且在注释掉导入时,一切都按预期工作。)

public class XmlDBResolver : XmlUrlResolver
{
    private IDictionary<string,string> GetUriComponents(String uri)
    {
        bool useXmlPre = false;
        uri = uri.Replace("db://", "");
        useXmlPre = uri.StartsWith("xml/");
        uri = uri.Replace("xml/", "");
        IDictionary<string, string> dict = new Dictionary<string, string>();
        string app = null, area = null, subArea = null;

        if (!String.IsNullOrWhiteSpace(uri))
        {
            string[] components = uri.Split('.');

            if (components == null)
                throw new Exception("Invalid Xslt URI");

            switch (components.Count())
            {
                case 3:
                    app = components[0];
                    break;
                case 4:
                    area = components[0];
                    app = components[1];
                    break;
                case 5:
                    subArea = components[0];
                    area = components[1];
                    app = components[2];
                    break;
                default:
                    throw new Exception("Invalid Xslt URI");
            }

            dict.Add("application", app);
            dict.Add("area", area);
            dict.Add("subArea", subArea);
            dict.Add("xmlPreTransform", String.Format("{0}", useXmlPre));
        }

        return dict;
    }

    public override System.Net.ICredentials Credentials
    {
        set { /* TODO: check if we need credentials */ }
    }

    public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
    {
        /*
         *  db://<app>.hist.org
         *  db://<area>.<app>.hist.org
         *  db://<subArea>.<area>.<app>.hist.org
         * 
         * */

        Tracing.TraceHelper.WriteLine(String.Format("GetEntity {0}", absoluteUri));

        XmlReader reader = null;

        switch (absoluteUri.Scheme)
        {
            case "db":
                string origString = absoluteUri.OriginalString;
                IDictionary<string, string> xsltDict = GetUriComponents(origString);

                if(String.IsNullOrWhiteSpace(xsltDict["area"]))
                {
                    reader = DatabaseServiceFactory.DatabaseService.GetApplicationXslt(xsltDict["application"]);
                }
                else if (!String.IsNullOrWhiteSpace(xsltDict["area"]) && String.IsNullOrWhiteSpace(xsltDict["subArea"]) && !Boolean.Parse(xsltDict["xmlPreTransform"]))
                {
                    reader = DatabaseServiceFactory.DatabaseService.GetAreaXslt(xsltDict["application"], xsltDict["area"]);
                }
                else if (!String.IsNullOrWhiteSpace(xsltDict["area"]) && !String.IsNullOrWhiteSpace(xsltDict["subArea"]))
                {
                    if(Boolean.Parse(xsltDict["xmlPreTransform"]))
                        reader = DatabaseServiceFactory.DatabaseService.GetSubareaXmlPreTransformXslt(xsltDict["application"], xsltDict["area"], xsltDict["subArea"]);
                    else
                        reader = DatabaseServiceFactory.DatabaseService.GetSubareaXslt(xsltDict["application"], xsltDict["area"], xsltDict["subArea"]);
                }
                return reader;

            default:
                return base.GetEntity(absoluteUri, role, ofObjectToReturn);
        }
    }

为了完整性,IDatabaseService 接口(相关部分):

public interface IDatabaseService
{
    ...
    XmlReader GetApplicationXslt(String applicationName);
    XmlReader GetAreaXslt(String applicationName, String areaName);
    XmlReader GetSubareaXslt(String applicationName, String areaName, String subAreaName);
    XmlReader GetSubareaXmlPreTransformXslt(String applicationName, String areaName, String subAreaName);
}

Update:我尝试通过临时从 Web 服务器加载样式表来隔离问题,这很有效。我了解到,与存储在 Web 服务器上的样式表相比,SQL Server 显然只存储没有 XML 声明的 XML 片段。

Update:异常的堆栈跟踪:

System.Xml.Xsl.XslLoadException:XSLT-Kompilierungsfehler。费勒 (9,1616)。 ---> System.ArgumentException:具有相同键的条目已存在.. bei System.Collections.Specialized.ListDictionary.Add(Object key, Object value) bei System.Collections.Specialized.HybridDictionary.Add(Object key, Object) value) 位于 System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include) 位于 System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(Uri uri, Boolean include) 位于 System.Xml.Xsl.Xslt.XsltLoader .LoadStylesheet(XmlReader reader, Boolean include) --- Ende der insideen Ablaufverfolgung des Ausnahmestacks --- bei System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include) bei System.Xml.Xsl.Xslt.XsltLoader .Load(XmlReader reader) 位于 System.Xml.Xsl.Xslt.XsltLoader.Load(Compiler 编译器、对象样式表、XmlResolver xmlResolver) 位于 System.Xml.Xsl.Xslt.Compiler.Compile(对象样式表、XmlResolver xmlResolver、QilExpression& qil) bei System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver) bei System.Xml.Xsl.XslCompiledTransform.Load(String stylesheetUri, XsltSettings settings, XmlResolver stylesheetResolver) bei (我的命名空间和类).GetXslTransform( Boolean preTransform) bei (我的命名空间和类).get_XslHtmlOutput() bei (我的命名空间和类).get_DisplayMarkup()


简短回答:

Your 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!
}

如果指定此参数,一切都可能正常工作。请参阅此答案的最后一部分,了解我为什么建议这样做。


长答案,介绍:可能的错误源:

我们首先简要思考一下哪些组件可能会导致错误:

“将 XSLT 文档从本地文件系统移动到数据库后,开始出现此错误。使用指向本地文件的默认导入方案以及从本地文件系统加载 XSLT 文档时,不会出现该错误。”

将样式表放入数据库意味着您必须拥有……

  1. 更改了样式表中的导入路径(引入了db://… paths)
  2. 实施并连接自定义XmlDbResolver用于处理db://进口方案
  3. 以以下形式实现数据库访问代码IDatabaseService,它支持XmlDbResolver

如果除导入路径外样式表未更改,则错误可能出在您的XmlResolver班级和/或在IDatabaseService执行。由于您尚未显示后者的代码,因此我们无法在不进行猜测的情况下调试您的代码。

我使用你创建了一个模拟项目XmlDbResolver(完整描述如下)。 我无法重现该错误,因此我怀疑您的IDatabaseService执行导致错误。

Update:我已经能够重现该错误。请参阅OP的评论和本答案的最后一部分。


我尝试重现您的错误:

我在 Visual Studio 2010 中创建了一个控制台应用程序项目(您可以通过克隆来检索该项目)这个要点 https://gist.github.com/stakx/fbbd5e7319bd6c281c50b4ebb1cee1f9使用 Git (git clone https://gist.github.com/fbbd5e7319bd6c281c50b4ebb1cee1f9.git)然后检查第二次提交,git checkout d00629)。我将在下面更详细地描述解决方案的每个项目。

(请注意,复制到输出目录的财产SqlServerDatabase.mdf, TestInput.xml,以及两者的.xslt项目项应设置为Always.)


SqlServerDatabase.mdf:

这是一个基于服务的数据库,我将把它附加到 SQL Server Express 2008 的本地实例。(这是通过中的连接字符串完成的)App.config;见下文。)

我已经在此数据库中设置了以下项目:

该表包含两列,定义如下:

表格最初是空的。测试数据将在运行时添加到数据库中(参见Program.cs and CommonHistOrg.xslt below).


应用程序配置:

该文件包含上述数据库的连接字符串条目。

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="SqlServerDatabase"
         connectionString="Data Source=.\SQLEXPRESS;
                           AttachDbFilename=|DataDirectory|\SqlServerDatabase.mdf;
                           Integrated Security=True;
                           User Instance=True"
         />
  </connectionStrings>
</configuration>

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)
}

XmlDbResolver.cs:

这包含XmlDbResolver类,与你的相同XmlDBResolver类除了两个变化:

  1. 公共构造函数接受IDatabaseService目的。这是用来代替DatabaseServiceFactory.DatabaseService.

  2. 我不得不删除对Tracing.TraceHelper.WriteLine.


CommonHistOrg.xslt:

这是db://common.hist.org样式表,将在运行时放入数据库(请参阅Program.cs below):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="Foo">
    <Bar/>
  </xsl:template>
</xsl:stylesheet>

测试样式表.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>

测试输入.xml:

这是我们将使用上面的内容转换的 XML 测试输入文档TestStylesheet.xslt:

<?xml version="1.0" encoding="utf-8" ?>
<Foo/>

程序.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 文档<Bar/>,这就是db://common.hist.org匹配的样式表输出<Foo/>来自测试输入的元素。


更新:错误重现和修复:

  1. 在下面的语句中插入Main method:

    databaseService.StoreApplicationDocument(
        applicationName: "test",
        document:        XmlReader.Create("TestStylesheet.xslt"));
    
  2. 代替

    xslt.Load(@"TestStylesheet.xslt", …);
    

    do

    xslt.Load(@"db://test.hist.org", …);
    

    这会触发 OP 报告的错误。

经过一番调试,我发现以下情况不会导致这个问题。

  • 事实是Document数据库表中的列具有类型XML。它失败了NTEXT, too.

  • 事实是<?xml … ?>从数据库返回的文档中缺少标头。即使之前手动添加了 XML 标头,该错误仍然存​​在SqlServerDatabaseService将控制权返回给框架。

事实上,该错误是在 .NET Framework 代码中的某个位置触发的。这就是为什么我决定下载并安装.NET框架参考源 http://referencesource.microsoft.com/。 (出于调试目的,我更改了解决方案以使用框架 3.5 版本。)安装此框架并重新启动 VS,然后您就可以在调试会话期间查看并单步执行框架代码。

从调用开始xslt.Load(…;) in our Main方法,我进入了框架代码,最终得出了一个方法LoadStylesheet inside XsltLoader.cs。有一个HybridDictionary called documentUrisInUse,它显然存储了已加载样式表的基本 URI。因此,如果我们加载多个带有空或缺失基本 URI 的样式表,此方法将尝试添加null查那本字典两次;这就是导致错误的原因。

因此,一旦您为您返回的每个样式表分配了唯一的基本 URIIDatabaseService,一切都应该工作正常。你可以通过传递一个来做到这一点baseUri to the XmlReader构造函数。请参阅我的答案开头的代码示例。您还可以通过以下方式检索更新的工作解决方案下载 https://gist.github.com/stakx/fbbd5e7319bd6c281c50b4ebb1cee1f9/archive/79efc4c57f4aeb490733c122da14b5a69fe86e8d.zip或克隆这个要点 https://gist.github.com/stakx/fbbd5e7319bd6c281c50b4ebb1cee1f9 (git clone https://gist.github.com/fbbd5e7319bd6c281c50b4ebb1cee1f9.git).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

XslCompiledTransform 和自定义 XmlUrlResolver:“具有相同键的条目已存在” 的相关文章

随机推荐

  • Android Google Maps V2 当前位置纬度经度 NullPointerException

    有很多类似的问题 但我没有找到解决我的问题的方法 setUpMap方法是 private void setUpMap BitmapDescriptor iconm BitmapDescriptorFactory fromResource R
  • 如何消除按钮和其他视图之间的额外间隙?

    当我创建按钮视图时 Android 总是在该按钮与其下方的其他视图之间创建一些额外的空间 在下面的示例中 第二个按钮上方有一个按钮 您可以看到这两个按钮之间的间隙 我怎样才能摆脱这个差距 谢谢
  • eclipse中终止调试/运行的快捷方式是什么?

    What is the shortcut in eclipse to terminate debugging running Looking under Preferences gt Keys says Ctrl F2 but it doe
  • PHP 命名空间 - 提升一个级别?

    示例1 命名空间 Inori Test 主测试类 示例2 命名空间 Inori Test SubTest SubTest 类扩展了 问题 有没有办法快速提升命名空间的级别 以便 SubTest 可以扩展 MainTest 就像是 MainT
  • 如果 netezza 中存在则删除

    我需要一个命令来删除表 如果存在 NETEZZA 类似这样的东西 drop table if exists xxx 我已经搜索并尝试了很多但没有成功 你能帮我一下吗 In netezza你可以使用这个语法 drop table table
  • iOS 所需的设备功能自动对焦相机

    我有一个 iOS 应用程序 我在其中设置Required Device Capabilities配置设置需要两者still camera and auto focus camera因为它需要在具有更好的自动对焦相机传感器的新一代设备上运行
  • Material-UI 中 IconButton 的悬停效果

    图标按钮悬停 https i stack imgur com lsYHX png 这是我正在使用的 Material UI 中的 iconButton 正如您所看到的 当您将鼠标悬停在图标上时 图标周围有一个轻微的灰色边框 禁用此功能的属性
  • 如何为单个函数设置 ICC 属性“fp-model precision”,以防止关联优化?

    我正在实施卡汉求和 http en wikipedia org wiki Kahan summation algorithm 在支持 gcc47 gcc48 clang33 icc13 和 icc14 编译的项目中 作为该算法的一部分 我想
  • Kubernetes Pod 已终止 - 退出代码 137

    我需要一些关于 k8s 1 14 和在其上运行 gitlab 管道所面临的问题的建议 许多作业都会抛出退出代码 137 错误 我发现这意味着容器突然终止 集群信息 库伯内特版本 1 14 使用的云 AWS EKS 节点 C5 4xLarge
  • 用于获取有关 SVN 存储库信息的 Python 库?

    我正在寻找一个可以从 SVN 存储库中提取 至少 以下信息的库 not工作副本 修订号及其作者和提交消息 每个修订版中的更改 添加 删除 修改文件 有Python库可以做到这一点吗 对于作者和提交消息 我可以解析 db revprops 0
  • 如何将上传的STEP文件转换为其他格式?

    如何将上传的 STEP 文件转换为其他 CAD 格式 最好使用 PHP 我将一个小型 STEP 文件上传到 3dContentCentral 并立即看到新上传的 STEP 文件的 20 种不同文件类型格式 示例网址 希望你们中的一些人能给我
  • 创建横幅交换算法来轮播广告

    我正在构建广告横幅轮播脚本基于印象整个月均匀地显示广告 每次请求显示广告时都会进行计算 所以这将是即时完成的 广告应显示为一个接一个轮流播放 而不是仅显示一个广告 1000 次展示 然后显示另一个广告 1000 次展示 大多数情况下 它应该
  • 将文件保存为 MYSQL 数据库中的 blob 或文件路径

    我知道这些问题是常见问题之一 但我需要您针对具体案例提供帮助 我正在开发一个应用程序 其中一些用户可以添加订单 一些用户可以执行这些订单 这些订单非常具体 因此只有有限数量的用户可以添加它们 然后 为每个订单生成三个文档 每个文档的大小不超
  • 尝试从输入流检索文本时应用程序挂起

    情况 我确实查看了您的代码 正如我怀疑的那样 您的问题与您发布的代码完全无关 您的 GUI 完全忽略 Swing 线程规则 并在主 Swing 事件线程 称为Event Dispatch T螺纹或EDT 由于该线程负责所有 Swing 绘图
  • Inno Setup:如何根据代码更改语言文件

    我使用自己的语言文件 isl 而不是使用 Inno Setup 的默认语言文件 它允许我自定义一些消息 但现在 我想要每种语言文件有两个版本 一个用于首次安装 一个用于更新 但是 是否可以从代码中选择一个文件 如果是 该怎么做 也许有一些比
  • Android 并获取 id 转换为字符串的视图

    在 Android 项目的 Java 代码中 如果您想要视图资源的引用 您可以执行以下操作 View addButton findViewById R id button 0 在上面的 R id button 0 不是一个字符串 是否可以通
  • @media查询和图像交换[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我希望在调整浏览器大小时网站中的图像完全改变 我一直在使用媒体查询 但我似乎无法正确使用它 有什么想法 建议吗 将来请添加您尝试过的代
  • IntelliJ:将“在路径中查找”范围限制为在 VCS 中跟踪的文件

    我想在 IntelliJ 中搜索整个项目目录 但将范围限制为在 VCS 中跟踪的文件 即我通过执行得到的结果相同git grep 我看到下面有一个自定义范围Find In Path gt Scope gt VCS Scopes gt Def
  • JQuery Mobile - 按钮

    如何使用 jquery mobile 禁用编码中的按钮 div Value div 注意 我想在编码中禁用该按钮 而不是在设计时 实例 http jsfiddle net LHG4L 5 http jsfiddle net LHG4L 5
  • XslCompiledTransform 和自定义 XmlUrlResolver:“具有相同键的条目已存在”

    有没有办法调试由自定义 XmlUrlResolver 从数据库加载的 XSLT 文档 或者有人知道下面的错误消息是关于什么的吗 我有一个导入通用 xslt 文档的 XSLT 样式表