规范化SQL Server中的XML以进行散列

时间:2012-10-02 10:42:39

标签: .net xml tsql sql-server-2005 xml-parsing

我问this question这导致我做了以下事情。

  • 创建C#对象结构的XML表示形式,以便将其传递给SQLServer。
  • 创建散列XML 的存储过程,然后将XML碎化为相关表,并将散列存储在根表中以便快速查找。

这意味着我可以将复杂的对象数据传递给SQLServer并对哈希进行查找,而不是尝试粉碎并将XML与表匹配(我也可以这样做但是速度慢(呃))... < / p>

然而 - 关于XML的一个好处是你可以格式化它,例如缩进等等 - 而且 - 属性顺序并不重要。但是当您对某些格式和缩进进行哈希处理时很重要。所以我在C#中做的是......

  • 通过按字母顺序排列所有属性来规范化XML
  • 使用.ToString(DisableFormatting)删除额外的格式空间

这很好用,但是当我测试它时,格式化 XML更容易,所以我可以更容易地看到我传递给存储过程的内容。

如果可以信任SQLServer来保存属性顺序but it can't ...

,那就太好了
  

不保留XML实例中的属性顺序。当你   查询存储在xml类型列中的XML实例的顺序   生成的XML中的属性可能与原始XML不同   实例

这意味着我无法使用SQLServer的XML数据类型来规范化数据。

让我感到困扰的是,某些人会在某个时候使用我的触发器并认为“哦,很棒,XML,属性顺序无关紧要,格式无关紧要,表示的数据是相同的“但是,当我哈希时,情况并非如此。

任何人都有解决这个问题的方法吗?我真的不想在T-SQL中编写XML解析器!或者使用其他人编写的XML解析器来规范化它。为什么SQLServer XML数据类型不能保留属性顺序?

我想我可以“信任”我的应用程序始终以相同的格式/顺序传递XML,从而导致相同对象的相同哈希。但我对于存储过程还必须“信任”应用程序来执行此操作的想法感到不安。我想以某种方式能够检查XML的规范化,它显然会更加健壮。

1 个答案:

答案 0 :(得分:0)

我将尝试序列化存储过程中的对象。

让我们来讨论以下课程:

class MyCustomObject 
{
    int id;
    string SomeField;
}

然后你可以使用一个存储过程,你在xml中序列化对象并计算输入参数的校验和,然后在另一个中你可以传递一个HashValue(校验和)和一个Xml。通过反序列化Xml,可以计算Xml中字段的校验和,并将其与传递的HashValue进行比较。

试试这段代码: (注意,您应该存储哈希值并将其返回给调用者并使用xml执行某些操作)

CREATE PROCEDURE HashObject(@id int, @SomeField varchar(255)) AS
BEGIN
    SELECT
        CHECKSUM(@id, @SomeField) AS CalculatedHashValue,
        (SELECT @id AS ID, @SomeField AS SomeField FOR XML RAW('xmlRowName')) AS Xml_Data,
        @id AS SPCall_ID,
        @SomeField AS SPCall_SomeField
END
GO

CREATE PROCEDURE CheckHash(@HashValue INT, @data XML) AS
BEGIN
    SELECT  
        CHECKSUM(rt.value('@ID', 'int'), rt.value('@SomeField', 'varchar(255)')) AS Xml_CalculatedHashValue,
        @data Xml_Data,
        rt.value('@ID', 'int') AS Xml_ID,
        rt.value('@SomeField', 'varchar(255)') AS Xml_SomeField,
        @HashValue AS SPCall_HashValue

    FROM @data.nodes('xmlRowName') AS nd(rt)

END
GO

DECLARE @id INT = 11
DECLARE @SomeField varchar(255) = 'string value'
DECLARE @data XML

EXEC dbo.HashObject @id, @SomeField

SET @data = (SELECT @id AS ID, @SomeField AS SomeField FOR XML RAW('xmlRowName'))
EXEC dbo.CheckHash 0, @data

SET @data = (SELECT 25 AS ID, 'diferent string value' AS SomeField FOR XML RAW('xmlRowName'))
EXEC dbo.CheckHash 0, @data
GO