XML File Validator Tool

<#
.SYNOPSIS
XML File Validator Tool

.DESCRIPTION
This script provides a tool to validate XML files, check for syntax errors,
analyze the structure, and perform various XML-related tasks.

.NOTES
File Name      : XMLValidator.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V5.1 or later
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
.\XMLValidator.ps1
#>

Add-Type -AssemblyName System.Xml.Linq

function Show-Menu {
    Clear-Host
    Write-Host "=== XML File Validator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Validate XML File"
    Write-Host "2. Analyze XML Structure"
    Write-Host "3. Search XML"
    Write-Host "4. Compare Two XML Files"
    Write-Host "5. Validate Against XSD Schema"
    Write-Host "6. Exit"
}

function Validate-XMLFile {
    $filePath = Read-Host "Enter the path to the XML file"
    if (-not (Test-Path $filePath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    try {
        [xml]$xml = Get-Content $filePath
        Write-Host "XML is valid." -ForegroundColor Green

        $size = (Get-Item $filePath).Length
        $elementCount = $xml.SelectNodes("//*").Count
        $attributeCount = $xml.SelectNodes("//@*").Count

        Write-Host "File Size: $size bytes"
        Write-Host "Number of Elements: $elementCount"
        Write-Host "Number of Attributes: $attributeCount"
    }
    catch [System.Xml.XmlException] {
        Write-Host "Invalid XML. Error details:" -ForegroundColor Red
        Write-Host $_.Exception.Message
    }
}

function Analyze-XMLStructure {
    $filePath = Read-Host "Enter the path to the XML file"
    if (-not (Test-Path $filePath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    try {
        [xml]$xml = Get-Content $filePath
        $structure = Get-XMLStructure $xml.DocumentElement
        Write-Host "XML Structure:" -ForegroundColor Yellow
        $structure | ForEach-Object { Write-Host $_ }
    }
    catch {
        Write-Host "Error analyzing XML structure: $_" -ForegroundColor Red
    }
}

function Get-XMLStructure($element, $indent = "") {
    $output = @()
    $output += "$indent$($element.Name)"
    
    if ($element.Attributes.Count -gt 0) {
        $attributes = $element.Attributes | ForEach-Object { "$($_.Name)='$($_.Value)'" }
        $output += "$indent  Attributes: $($attributes -join ', ')"
    }
    
    foreach ($child in $element.ChildNodes) {
        if ($child.NodeType -eq [System.Xml.XmlNodeType]::Element) {
            $output += Get-XMLStructure $child "$indent  "
        }
        elseif ($child.NodeType -eq [System.Xml.XmlNodeType]::Text) {
            $output += "$indent  Text: $($child.Value.Trim())"
        }
    }
    
    return $output
}

function Search-XML {
    $filePath = Read-Host "Enter the path to the XML file"
    if (-not (Test-Path $filePath)) {
        Write-Host "File not found." -ForegroundColor Red
        return
    }

    $searchTerm = Read-Host "Enter the search term (element or attribute name)"

    try {
        [xml]$xml = Get-Content $filePath
        $results = $xml.SelectNodes("//*[local-name()='$searchTerm'] | //@*[local-name()='$searchTerm']")
        
        if ($results.Count -eq 0) {
            Write-Host "No results found for: $searchTerm" -ForegroundColor Yellow
        }
        else {
            Write-Host "Search Results:" -ForegroundColor Green
            foreach ($result in $results) {
                Write-Host "XPath: $($result.XPath)"
                if ($result.NodeType -eq [System.Xml.XmlNodeType]::Element) {
                    Write-Host "Element Value: $($result.InnerXml)"
                }
                elseif ($result.NodeType -eq [System.Xml.XmlNodeType]::Attribute) {
                    Write-Host "Attribute Value: $($result.Value)"
                }
                Write-Host "---"
            }
        }
    }
    catch {
        Write-Host "Error searching XML: $_" -ForegroundColor Red
    }
}

function Compare-XMLFiles {
    $filePath1 = Read-Host "Enter the path to the first XML file"
    $filePath2 = Read-Host "Enter the path to the second XML file"

    if (-not (Test-Path $filePath1) -or -not (Test-Path $filePath2)) {
        Write-Host "One or both files not found." -ForegroundColor Red
        return
    }

    try {
        $xml1 = [System.Xml.Linq.XDocument]::Load($filePath1)
        $xml2 = [System.Xml.Linq.XDocument]::Load($filePath2)

        $differences = Compare-XmlDocs $xml1 $xml2

        if ($differences.Count -eq 0) {
            Write-Host "The XML files are identical." -ForegroundColor Green
        }
        else {
            Write-Host "Differences found:" -ForegroundColor Yellow
            foreach ($diff in $differences) {
                Write-Host "XPath: $($diff.XPath)"
                Write-Host "File 1 Value: $($diff.Value1)"
                Write-Host "File 2 Value: $($diff.Value2)"
                Write-Host "---"
            }
        }
    }
    catch {
        Write-Host "Error comparing XML files: $_" -ForegroundColor Red
    }
}

function Compare-XmlDocs($doc1, $doc2) {
    $differences = @()
    $elements1 = $doc1.Descendants()
    $elements2 = $doc2.Descendants()

    foreach ($element in $elements1) {
        $xpath = $element.XPathSelectElement($element.GetAbsoluteXPath())
        $otherElement = $doc2.XPathSelectElement($xpath.GetAbsoluteXPath())

        if ($null -eq $otherElement) {
            $differences += @{XPath = $xpath.GetAbsoluteXPath(); Value1 = $element.Value; Value2 = "Element not found"}
        }
        elseif ($element.Value -ne $otherElement.Value) {
            $differences += @{XPath = $xpath.GetAbsoluteXPath(); Value1 = $element.Value; Value2 = $otherElement.Value}
        }

        foreach ($attr in $element.Attributes()) {
            $otherAttr = $otherElement?.Attribute($attr.Name)
            if ($null -eq $otherAttr) {
                $differences += @{XPath = "$($xpath.GetAbsoluteXPath())/@$($attr.Name)"; Value1 = $attr.Value; Value2 = "Attribute not found"}
            }
            elseif ($attr.Value -ne $otherAttr.Value) {
                $differences += @{XPath = "$($xpath.GetAbsoluteXPath())/@$($attr.Name)"; Value1 = $attr.Value; Value2 = $otherAttr.Value}
            }
        }
    }

    foreach ($element in $elements2) {
        $xpath = $element.XPathSelectElement($element.GetAbsoluteXPath())
        $otherElement = $doc1.XPathSelectElement($xpath.GetAbsoluteXPath())

        if ($null -eq $otherElement) {
            $differences += @{XPath = $xpath.GetAbsoluteXPath(); Value1 = "Element not found"; Value2 = $element.Value}
        }

        foreach ($attr in $element.Attributes()) {
            $otherAttr = $otherElement?.Attribute($attr.Name)
            if ($null -eq $otherAttr) {
                $differences += @{XPath = "$($xpath.GetAbsoluteXPath())/@$($attr.Name)"; Value1 = "Attribute not found"; Value2 = $attr.Value}
            }
        }
    }

    return $differences
}

function Validate-XMLAgainstXSD {
    $xmlPath = Read-Host "Enter the path to the XML file"
    $xsdPath = Read-Host "Enter the path to the XSD schema file"

    if (-not (Test-Path $xmlPath) -or -not (Test-Path $xsdPath)) {
        Write-Host "One or both files not found." -ForegroundColor Red
        return
    }

    try {
        $xmlReader = [System.Xml.XmlReader]::Create($xmlPath)
        $schemaReader = [System.Xml.XmlReader]::Create($xsdPath)
        $schema = [System.Xml.Schema.XmlSchema]::Read($schemaReader, $null)

        $settings = New-Object System.Xml.XmlReaderSettings
        $settings.ValidationType = [System.Xml.ValidationType]::Schema
        $settings.Schemas.Add($schema) | Out-Null

        $settings.ValidationEventHandler = {
            param($sender, $e)
            Write-Host "Validation Error: $($e.Message)" -ForegroundColor Red
        }

        $validatingReader = [System.Xml.XmlReader]::Create($xmlPath, $settings)
        while ($validatingReader.Read()) { }

        Write-Host "XML is valid according to the XSD schema." -ForegroundColor Green
    }
    catch {
        Write-Host "Error validating XML against XSD: $_" -ForegroundColor Red
    }
    finally {
        if ($null -ne $xmlReader) { $xmlReader.Close() }
        if ($null -ne $schemaReader) { $schemaReader.Close() }
        if ($null -ne $validatingReader) { $validatingReader.Close() }
    }
}

# Extension method to get absolute XPath
Add-Type @"
using System.Xml.Linq;
using System.Linq;

public static class XElementExtensions
{
    public static string GetAbsoluteXPath(this XElement element)
    {
        if (element == null)
            return string.Empty;

        var ancestors = element.AncestorsAndSelf().Reverse().ToList();
        return "/" + string.Join("/", ancestors.Select(e => e.Name.LocalName));
    }
}
"@

# Main program loop
do {
    Show-Menu
    $choice = Read-Host "`nEnter your choice (1-6)"

    switch ($choice) {
        "1" { Validate-XMLFile }
        "2" { Analyze-XMLStructure }
        "3" { Search-XML }
        "4" { Compare-XMLFiles }
        "5" { Validate-XMLAgainstXSD }
        "6" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

    if ($choice -ne "6") {
        Read-Host "`nPress Enter to continue..."
    }
} while ($choice -ne "6")

This XML File Validator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Functions to perform various XML-related tasks:
    • Validate XML files and provide basic statistics
    • Analyze and display the structure of XML files
    • Search for specific elements or attributes within XML files
    • Compare two XML files and highlight differences
    • Validate XML against an XSD schema

Key features:

  1. XML Validation:
    • Checks if the XML is syntactically valid
    • Provides file size, number of elements, and number of attributes
  2. XML Structure Analysis:
    • Displays a hierarchical view of the XML structure
    • Shows element names, attributes, and text content
  3. XML Search:
    • Allows searching for specific elements or attributes within the XML
    • Displays the XPath and value of found elements/attributes
  4. XML Comparison:
    • Compares two XML files
    • Highlights differences, including added, removed, or modified elements and attributes
  5. XSD Schema Validation:
    • Validates an XML file against an XSD schema
    • Reports any validation errors

This tool is particularly useful for:

  • Developers working with XML data
  • QA engineers validating XML outputs
  • Data analysts examining XML structures
  • Anyone needing to quickly validate, analyze, or compare XML files

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the menu options to select the desired function
  3. Provide the path to the XML file(s) when prompted
  4. Review the output for validation results, structure analysis, search results, file comparisons, or schema validation

This script provides a comprehensive set of tools for working with XML files, making it easier to validate, understand, and compare XML data without having to manually parse the files or use multiple tools.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *