【问题标题】:Is There Better Way to Validate SqlXml in CLR?是否有更好的方法在 CLR 中验证 SqlXml?
【发布时间】:2013-09-17 05:03:53
【问题描述】:

我需要针对 xsd 验证 sql server 中的 xml。 xsd 太复杂,无法与 XML SCHEMA COLLECTION 一起使用,所以我正在编写一个 SQL CLR 函数来完成它。我对如何“不得不”编写代码有两个问题。代码是针对 2.0 的 VB.NET,顺便说一句,尽管我认为我在 C# 中遇到了同样的问题。如果不乐意切换。

[1] 我似乎无法将设置附加到由 SqlXml.CreateReader 创建的阅读器,因此我必须加载到 XmlDocument 中才能执行验证。我也不能直接将 SqlXml 加载到 XmlDocument 中——我必须进行额外的类型转换。

是我遗漏了什么还是事情就是这样?

[2] 我讨厌我使用共享成员将验证结果从事件处理程序传递给调用方。这在我的第一个特定用法中很好,我知道有一系列单独的调用。但是,如果我曾经尝试将它与多个调用者一起使用或在集合操作中使用,我担心结果会令人怀疑。

有没有办法解决这个问题?

Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Xml
Imports System.Xml.Schema

Partial Public Class UserDefinedFunctions
  'this is from an ms sample
  Const TARGET_NAMESPACE As String = "http://www.contoso.com/books" 
  Const SCHEMA_URI As String = "D:\temp\temp.xsd"

  Shared schemaSet As XmlSchemaSet
  Shared schemaValidationEventHandler As ValidationEventHandler
  Shared isValid As Boolean
  Shared doc As XmlDocument

  Shared Sub New()
    schemaSet = New XmlSchemaSet
    schemaSet.Add(TARGET_NAMESPACE, SCHEMA_URI)
    schemaSet.Compile()

    doc = New XmlDocument
    doc.Schemas = schemaSet

    schemaValidationEventHandler = New ValidationEventHandler(
                                   AddressOf ValidationCallBack)
  End Sub

  <SqlFunction()> _
  Public Shared Function ValidateWithContosoXsd(ByVal xml As SqlXml) _
                                                         As SqlBoolean
    isValid = True

    Dim reader As XmlReader = xml.CreateReader
    reader.Settings.ValidationType = ValidationType.Schema

    doc.Load(reader)
    doc.Validate(schemaValidationEventHandler)

    ValidateWithContosoXsd = isValid
  End Function

  Private Shared Sub ValidationCallBack(ByVal sender As Object,
                                        ByVal args As ValidationEventArgs)
    isValid = False
  End Sub
End Class

我确实遵循了一条线索,尝试使用初始阅读器作为第二个阅读器的基础,该阅读器在大致等效的控制台应用程序中工作。控制台应用程序的不同之处在于,第一个准备就绪是来自文件 uri 而不是来自 SqlXml。可悲的是,当在 clr 中完成时,这总是显示有效。

Partial Public Class UserDefinedFunctions

    Const TARGET_NAMESPACE As String = "http://www.contoso.com/books"
    Const SCHEMA_URI As String = "D:\temp\temp.xsd"

    Shared settings As XmlReaderSettings
    Shared schemaSet As XmlSchemaSet
    Shared schemaValidationEventHandler As ValidationEventHandler
    Shared isValid As Boolean

    Shared Sub New()

        schemaSet = New XmlSchemaSet
        schemaSet.Add(TARGET_NAMESPACE, SCHEMA_URI)
        schemaSet.Compile()

        schemaValidationEventHandler = New ValidationEventHandler(AddressOf ValidationCallBack)

        settings = New XmlReaderSettings
        settings.Schemas = schemaSet
        settings.ValidationType = ValidationType.Schema
        AddHandler settings.ValidationEventHandler, schemaValidationEventHandler

    End Sub

    <SqlFunction()> _
    Public Shared Function ValidateWithContosoXsd(ByVal xml As SqlXml) As SqlBoolean

        isValid = True

        Dim baseReader As XmlReader = xml.CreateReader
        Dim reader As XmlReader = XmlReader.Create(baseReader, settings)

        While reader.Read()
        End While

        ValidateWithContosoXsd = isValid

    End Function

    Private Shared Sub ValidationCallBack(ByVal sender As Object, ByVal args As ValidationEventArgs)
        isValid = False
    End Sub
End Class

【问题讨论】:

    标签: c# .net sql-server vb.net sqlclr


    【解决方案1】:

    我仍然希望对第二个问题有想法,但我可以回答问题的第一部分。也许我应该把它分成一个单独的问题。

    [编辑:也想出了第二个问题。见下文。]

    我以某种方式掩盖了一个模糊的错误:System.InvalidOperationException:无法将一致性检查更改为 Document。确保 XmlReaderSettings 中的 ConformanceLevel 设置为 Auto 以用于包装场景。

    解决导致下面的工作代码。它还有一些其他的变化,但关键是 settings.ConformanceLevel = ConformanceLevel.Auto。

    <SqlFunction()> _
    Public Shared Function ResetSchema(ByVal targetNameSpace As SqlString, ByVal schemaUri As SqlString) As Boolean
        Dim result As Boolean
    
        Try
            schemaSet = New XmlSchemaSet
            schemaSet.Add(targetNameSpace, schemaUri)
            schemaSet.Compile()
    
            settings = New XmlReaderSettings
            settings.Schemas = schemaSet
            settings.ValidationType = ValidationType.Schema
            settings.ConformanceLevel = ConformanceLevel.Auto
            settings.ValidationFlags = settings.ValidationFlags Or XmlSchemaValidationFlags.ReportValidationWarnings
            AddHandler settings.ValidationEventHandler, AddressOf ValidationCallBack
    
            result = True
        Catch
            'result = False
        End Try
    
        ResetSchema = result
    End Function
    
    Public Shared Function ValidateWithXsd(ByVal xml As SqlXml) As SqlBoolean
        Try
    
            isValid = True
    
            Dim reader As XmlReader = xml.CreateReader
            Dim validatingReader As XmlReader = XmlReader.Create(reader, settings)
    
            While validatingReader.Read
            End While
    
        Catch ex As Exception
            Throw ex
        Finally
            ValidateWithXsd = isValid
        End Try
    
    End Function
    
    Private Shared Sub ValidationCallBack(ByVal sender As Object, ByVal args As ValidationEventArgs)
        isValid = False
    End Sub
    

    至于第二个问题,我将实际验证移至第二个朋友班。我仍然保留模式缓存,但可以使用该函数进行基于集合的操作。

    我不会将更改发布到主要课程,因为它们非常微不足道,但是新课程:

    Friend Class SchemaValidator
    
    Private isValid As Boolean
    
    Friend Function Validate(ByVal baseReader As XmlReader, ByVal settings As XmlReaderSettings) As Boolean
        Try
    
            isValid = True
            AddHandler settings.ValidationEventHandler, AddressOf ValidationEventHandler
            Dim validatingReader As XmlReader = XmlReader.Create(baseReader, settings)
    
            While validatingReader.Read
            End While
    
        Catch ex As Exception
            Throw ex
        Finally
            RemoveHandler settings.ValidationEventHandler, AddressOf ValidationEventHandler
            Validate = isValid
        End Try
    
    End Function
    
    Private Sub ValidationEventHandler(ByVal sender As Object, ByVal args As ValidationEventArgs)
        isValid = False
    End Sub
    End Class
    

    【讨论】:

      猜你喜欢
      • 2015-09-05
      • 2010-09-15
      • 1970-01-01
      • 2019-06-27
      • 2011-10-31
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多