Click here to Skip to main content
15,891,529 members
Articles / Programming Languages / XML

Validating data with Flat File Checker

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
30 Oct 2009GPL32 min read 43.7K   881   17  
An article on data validation with a flat file schema generated in Flat File Checker.
Imports System.Data.OleDb
Imports System.Threading
Imports System.Xml.XPath
Imports System.Xml

Public Class TemplateFields
    Implements IEnumerable(Of TemplateField)
    Private _fields As List(Of TemplateField)
    Friend Sub New()
        _fields = New List(Of TemplateField)
    End Sub
    Friend Sub Add(ByVal field As TemplateField)
        _fields.Add(field)
    End Sub
    Friend Sub add(ByVal field As FieldCondition, ByVal attribute As String)

        _fields.Add(New TemplateField(field, attribute))
    End Sub
    Friend Sub add(ByVal field As FieldCondition, ByVal attribute As String, ByVal hasCondition As Boolean)

        _fields.Add(New TemplateField(field, attribute, hasCondition))
    End Sub
    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of TemplateField) Implements System.Collections.Generic.IEnumerable(Of TemplateField).GetEnumerator
        Return _fields.GetEnumerator
    End Function
    Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return _fields.GetEnumerator
    End Function
End Class
Public Class TemplateField
    Private _field As ValueFieldCondition
    Private _attribute As String
    Private _has_condition As Boolean
    Friend Sub New(ByVal field As ValueFieldCondition, ByVal attribute As String)
        Me.New(field, attribute, False)
    End Sub
    Friend Sub New(ByVal field As ValueFieldCondition, ByVal attribute As String, ByVal hasCondition As Boolean)
        _field = field
        _attribute = attribute
        _has_condition = hasCondition
    End Sub

    Public ReadOnly Property Field() As ValueFieldCondition
        Get
            Return _field
        End Get
    End Property
    Public ReadOnly Property Attribute() As String
        Get
            Return _attribute
        End Get
    End Property
    Public ReadOnly Property HasCondition() As Boolean
        Get
            Return _has_condition
        End Get
    End Property
    ''' <summary>
    ''' Value as it is given in the XML schema, not evaluated.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property OriginalValue() As String
        Get
            Return _field.Value
        End Get
    End Property
    ''' <summary>
    '''  Value evaluated from expression given in the schema.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Value() As String
        Get
            Return _field.SecondValue
        End Get
    End Property
End Class
''' <summary>
''' Class makes it possible to create custom validations against external data sources (oledb connection). 
''' </summary>
''' <remarks>Rule object is created from template file.</remarks>
Public Class CustomQueryTemplate
    Private _name As String
    Private _messages As Collection
    Private _template_fields As TemplateFields
    Private _parent As QueryChecker
    Public Sub New(ByVal queryName As String, ByVal parent As QueryChecker)
        _parent = parent
        _template_fields = New TemplateFields
        _name = queryName
        Me.GetMessages(parent.Template)

        Dim iterator As XPathNodeIterator
        Dim fieldNavigator As XPathNavigator
        ' Set Table name of the Query Checker
        iterator = parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & queryName & "']/Source/From")
        For Each fieldNavigator In iterator
            _parent.TableName = fieldNavigator.InnerXml
        Next
        ' Add relevant fields
        iterator = parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & queryName & "']/Source/WhereFields/*[not(@Attribute)]")
        For Each fieldNavigator In iterator
            _parent.AddField(fieldNavigator)
        Next

    End Sub
    Public ReadOnly Property Fields() As TemplateFields
        Get
            Return _template_fields
        End Get
    End Property
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property
    ''' <summary>
    ''' Initates new Query Template from Xml definition
    ''' </summary>
    ''' <param name="definition">Template definition.</param>
    ''' <param name="parent">Query validation rule that uses the template.</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal definition As IXPathNavigable, ByVal parent As QueryChecker)
        _parent = parent
        _template_fields = New TemplateFields
        ' This should be single a node with several attributes.
        Dim navigator As XPathNavigator = definition.CreateNavigator
        _name = navigator.LocalName

        Me.GetMessages(parent.Template)

        Dim iterator As XPathNodeIterator = parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & _name & "']/Source")
        Select Case iterator.Count ' Number of templates for specified template & name
            Case 1 ' There is only one, so we are happy to proceed.
                iterator.MoveNext() ' Get to the first record
                Dim templateNavigator As XPathNavigator
                templateNavigator = iterator.Current() ' get navigator  (we are at Source level of the template)
                Dim fromNavigator As XPathNavigator = templateNavigator.CreateNavigator()
                fromNavigator.MoveToChild("From", "")
                parent.TableName = fromNavigator.InnerXml ' Get table or join clause name 

                Dim fieldsIterator As XPathNodeIterator = templateNavigator.Select("WhereFields/*")
                Dim fieldNavigator As XPathNavigator
                Dim attributeName As String ' this is an attribute name
                Dim field As FieldCondition
                For Each fieldNavigator In fieldsIterator
                    attributeName = fieldNavigator.GetAttribute("Attribute", "")
                    If String.IsNullOrEmpty(attributeName) Then
                        parent.AddField(fieldNavigator)
                    Else
                        Dim templateAttribute As XPathNavigator = navigator.CreateNavigator
                        If templateAttribute.MoveToAttribute(attributeName, "") Then
                            ' Parameter value provided in the node.
                            ' ie: <Contact Surname="Smith" />
                            field = New ValueFieldCondition(fieldNavigator, parent, navigator.GetAttribute(attributeName, ""))
                            ' there is an attribute with a name from template in our schema. now we are ready to add the field.
                            parent.AddField(field)
                            _template_fields.Add(New TemplateField(field, attributeName, True))

                        Else ' Check wehter there is a node with parameter definition
                            '
                            ' If condition is not provided in the template then parameter value 
                            ' should be provided in the separate node
                            ' ie: <Contact><Parameter Name="Surname" Value="Smith" Condition="=" /></Contact>
                            '
                            Dim paramIterator As XPathNodeIterator = navigator.Select("Parameter[@Name='" & attributeName & "']")
                            Dim paramNavigator As XPathNavigator
                            If paramIterator.Count = 1 Then
                                For Each paramNavigator In paramIterator
                                    Dim paramValue As String = paramNavigator.GetAttribute("Value", "")
                                    Dim paramCondition As EnumOperator = Condition.GetOperatorType(paramNavigator.GetAttribute("Condition", ""), paramValue)
                                    field = New ValueFieldCondition(fieldNavigator, parent, paramValue, paramCondition)
                                    parent.AddField(field)
                                    _template_fields.Add(field, attributeName)
                                Next
                            End If

                            ' ok there is no attribute with this name. That just means that we don't add these field to the rule.
                        End If
                    End If
                Next

            Case 0
                Throw New XmlException("Template: " & _name & " not found for the template:" & Me._parent.Template.Name)
            Case Else
                Throw New XmlException("Several templates with the same name: " & _name & " for the template:" & _parent.Template.Name)
        End Select
    End Sub
   
    Friend Sub AddField(ByVal queryName As String, ByVal attributeName As String, ByVal value As String, ByVal cond As EnumOperator)
        Dim iterator As XPathNodeIterator = _parent.Template.CreateNavigator.Select("Templates/Template[@Name='" & queryName & "']/Source/WhereFields/ValueField[@Attribute='" & attributeName & "']")
        If iterator.Count = 1 Then
            iterator.MoveNext()

            Dim fieldNavigator As XPathNavigator = iterator.Current
            Dim field As ValueFieldCondition = New ValueFieldCondition(fieldNavigator, _parent, value, cond)
            Dim cc As String = fieldNavigator.GetAttribute("Condition", "")
            Dim hasCondition As Boolean = Not String.IsNullOrEmpty(cc)
            ' there is an attribute with a name from template in our schema. now we are ready to add the field.
            _parent.AddField(field)
            _template_fields.Add(field, attributeName, hasCondition)
        Else
            Throw New XmlException("There must be one node where template name: " & Me.Template.Name & " and Attribute: " & attributeName)
        End If
    End Sub
    Friend Function GetNode() As System.Xml.XmlNode
        Dim customXml As XmlElement = _parent.Document.CreateElement(_name)

        Dim field As TemplateField
        For Each field In Me._template_fields
            If field.HasCondition Then
                ' Condition is set in the template
                ' so value can be provided in-line in the same node
                XmlNodeAppendAttribute(customXml, field.Attribute, field.Value)

            Else ' Condition is not set in the tempalte
                ' so child node should be created
                Dim parameterXml As XmlElement = _parent.Document.CreateElement("Parameter")

                XmlNodeAppendAttribute(parameterXml, "Name", field.Attribute)

                If Not String.IsNullOrEmpty(field.OriginalValue) Then
                    XmlNodeAppendAttribute(parameterXml, "Value", field.OriginalValue)
                End If
                XmlNodeAppendAttribute(parameterXml, "Condition", Condition.GetOperatorType(field.Field.Condition))

                customXml.AppendChild(parameterXml)

            End If

        Next
        Return customXml
    End Function
   
    Private Sub GetMessages(ByVal template As IXPathNavigable)
        Dim navigator As XPathNavigator = template.CreateNavigator
        Dim iterator As XPathNodeIterator
        If _messages Is Nothing Then _messages = New Collection
        iterator = navigator.Select("Templates/Template[@Name='" & _name & "']/Messages/*")
        While iterator.MoveNext
            navigator = iterator.Current

            If _messages.Count > 0 AndAlso _messages.Contains(navigator.LocalName) Then
                _messages.Remove(navigator.LocalName)
            End If
            _messages.Add(navigator.InnerXml, navigator.LocalName)
        End While
    End Sub
    Public ReadOnly Property DataRuleMessage() As String
        Get
            Dim message As String
            Select Case _parent.Cardinality
                Case CardinalityType.Exists
                    message = CStr(Me._messages("Exists"))
                Case CardinalityType.Condition
                    message = CStr(Me._messages("Cardinality"))
                Case CardinalityType.NotExists
                    message = CStr(Me._messages("NotExists"))
                Case Else
                    message = "Wrong type of query rule."
            End Select
            message &= "("
            Dim field As TemplateField
            Dim first_field As Boolean = True
            For Each field In Me._template_fields
                If first_field Then
                    first_field = False
                    message &= field.Attribute & "=" & field.Value
                Else
                    message &= ", " & field.Attribute & "=" & field.Value
                End If
            Next
            message &= ")"
            Return message
        End Get
    End Property
    Friend ReadOnly Property Template() As Template
        Get
            Return Me._parent.Template
        End Get

    End Property

End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Database Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions