From aacaaee49371b20345341cbdbf3b54d722ada020 Mon Sep 17 00:00:00 2001 From: Frederik Jacobsen Date: Sun, 19 Oct 2025 00:05:28 +0200 Subject: [PATCH] Started working on documentation --- .../ViewModels/MainWindowViewModel.cs | 14 +++++++ .../Views/LeftTreeView.axaml.cs | 12 ++---- XSDVisualiser/Models/AttributeInfo.cs | 20 +++++++++- XSDVisualiser/Models/ConstraintSet.cs | 7 +++- XSDVisualiser/Models/SchemaNode.cs | 16 ++++---- XSDVisualiser/Parsing/XsdSchemaParser.cs | 11 ++++- XSDVisualiser/Utils/XmlValidation.cs | 40 +++++++++++++++++++ 7 files changed, 101 insertions(+), 19 deletions(-) diff --git a/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs b/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs index 7b24482..93d28b2 100644 --- a/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs +++ b/XSDVisualiser.Desktop/ViewModels/MainWindowViewModel.cs @@ -4,6 +4,10 @@ using XSDVisualiser.Core; namespace XSDVisualiser.Desktop.ViewModels; +/// +/// View model exposing the parsed schema for binding in the main window. +/// Provides selection state and information about the currently loaded XSD file. +/// public class MainWindowViewModel(SchemaModel model) : INotifyPropertyChanged { private string? _currentFilePath; @@ -11,6 +15,10 @@ public class MainWindowViewModel(SchemaModel model) : INotifyPropertyChanged private SchemaNode? _selectedNode; private SchemaNode? _selectedRootElement; + /// + /// Parsed schema model currently displayed by the UI. + /// Setting this property updates dependent properties and notifies bindings. + /// public SchemaModel Model { get => _model; @@ -24,8 +32,14 @@ public class MainWindowViewModel(SchemaModel model) : INotifyPropertyChanged } } + /// + /// All global elements defined in the loaded schema. + /// public IEnumerable RootElements => _model?.RootElements ?? Enumerable.Empty(); + /// + /// If set, filters the view to show only this root element and its subtree. + /// public SchemaNode? SelectedRootElement { get => _selectedRootElement; diff --git a/XSDVisualiser.Desktop/Views/LeftTreeView.axaml.cs b/XSDVisualiser.Desktop/Views/LeftTreeView.axaml.cs index b24ee8b..58f71cd 100644 --- a/XSDVisualiser.Desktop/Views/LeftTreeView.axaml.cs +++ b/XSDVisualiser.Desktop/Views/LeftTreeView.axaml.cs @@ -15,6 +15,10 @@ using XSDVisualiser.Desktop.ViewModels; namespace XSDVisualiser.Desktop.Views; +/// +/// Left-side tree view control that displays parsed XSD schema nodes and provides actions +/// such as copy-as-TSV, validate against XML, and export sample XML. +/// public partial class LeftTreeView : UserControl { public LeftTreeView() @@ -24,7 +28,6 @@ public partial class LeftTreeView : UserControl private async void OnCopyAsTsvClick(object? sender, RoutedEventArgs e) { - // Determine the node from the menu item's DataContext var node = (sender as MenuItem)?.DataContext as SchemaNode; if (node == null) node = @@ -40,7 +43,6 @@ public partial class LeftTreeView : UserControl private async void OnValidateAgainstXmlClick(object? sender, RoutedEventArgs e) { - // Resolve node from context var node = (sender as MenuItem)?.DataContext as SchemaNode; if (node == null) node = (sender as Control)?.GetVisualAncestors().OfType().FirstOrDefault()?.DataContext as SchemaNode; @@ -96,7 +98,6 @@ public partial class LeftTreeView : UserControl private static string BuildTsv(SchemaNode root) { var sb = new StringBuilder(); - // Header sb.AppendLine( "Depth\tPath\tName\tNamespace\tTypeName\tBuiltInType\tMinOccurs\tMaxOccurs\tContentModel\tConstraints\tIsNillable"); var initialPath = root.Name ?? string.Empty; @@ -146,7 +147,6 @@ public partial class LeftTreeView : UserControl private static async Task TryGetLocalPathAsync(IStorageFile file) { - // Avalonia provides TryGetLocalPath extension for local files; otherwise, we can't access it via System.IO API. return file.TryGetLocalPath(); } @@ -183,10 +183,8 @@ public partial class LeftTreeView : UserControl } }; - // Compose content if (dialog.Content is Grid grid) { - // Use a read-only TextBox so users can select text easily var textBox = new TextBox { Text = text, @@ -198,7 +196,6 @@ public partial class LeftTreeView : UserControl var scroller = new ScrollViewer { Content = textBox }; - // Copy button var copyButton = new Button { Content = "Copy", @@ -212,7 +209,6 @@ public partial class LeftTreeView : UserControl if (topLevel?.Clipboard != null) { await topLevel.Clipboard.SetTextAsync(text); - // Provide lightweight feedback by changing content briefly if (copyButton.Content is string) copyButton.Content = "Copied"; await Task.Delay(1000); diff --git a/XSDVisualiser/Models/AttributeInfo.cs b/XSDVisualiser/Models/AttributeInfo.cs index e377aae..991bc12 100644 --- a/XSDVisualiser/Models/AttributeInfo.cs +++ b/XSDVisualiser/Models/AttributeInfo.cs @@ -7,15 +7,33 @@ namespace XSDVisualiser.Core; /// public class AttributeInfo { + /// + /// Local name of the attribute. + /// [XmlAttribute] public string? Name { get; set; } + /// + /// Namespace URI of the attribute, if any. + /// [XmlAttribute] public string? Namespace { get; set; } - [XmlAttribute] public string? Use { get; set; } // optional | required | prohibited + /// + /// Usage of the attribute: optional | required | prohibited. + /// + [XmlAttribute] public string? Use { get; set; } + /// + /// The qualified type name if the attribute has a named type. + /// [XmlAttribute] public string? TypeName { get; set; } + /// + /// Built-in XML Schema type code name when applicable. + /// [XmlAttribute] public string? BuiltInType { get; set; } + /// + /// Optional constraints applied to the attribute's simple type. + /// [XmlElement] public ConstraintSet? Constraints { get; set; } } \ No newline at end of file diff --git a/XSDVisualiser/Models/ConstraintSet.cs b/XSDVisualiser/Models/ConstraintSet.cs index 2701cd9..04f8a8c 100644 --- a/XSDVisualiser/Models/ConstraintSet.cs +++ b/XSDVisualiser/Models/ConstraintSet.cs @@ -7,9 +7,14 @@ namespace XSDVisualiser.Core; /// public class ConstraintSet { + /// + /// The qualified name of the base type this constraint set applies to, if any. + /// [XmlAttribute] public string? BaseTypeName { get; set; } - // Generic catch-all list of constraints for dynamic display and tooling + /// + /// A catch-all list of constraint entries for dynamic display and tooling. + /// [XmlArray("Constraints")] [XmlArrayItem("Constraint")] public List Constraints { get; set; } = new(); diff --git a/XSDVisualiser/Models/SchemaNode.cs b/XSDVisualiser/Models/SchemaNode.cs index 6766a7e..72cb53d 100644 --- a/XSDVisualiser/Models/SchemaNode.cs +++ b/XSDVisualiser/Models/SchemaNode.cs @@ -29,7 +29,10 @@ public class SchemaNode [XmlArrayItem("Element")] public List Children { get; set; } = new(); - [XmlAttribute] public string? ContentModel { get; set; } // sequence | choice | all | simple + /// + /// Content model for this node: sequence | choice | all | simple. For synthetic group nodes, may be "group". + /// + [XmlAttribute] public string? ContentModel { get; set; } /// /// Human-readable documentation extracted from xsd:annotation/xsd:documentation. @@ -38,14 +41,13 @@ public class SchemaNode [XmlElement] public string? Documentation { get; set; } + /// + /// Returns a human-readable name for UI elements (prefers Name, then TypeName). + /// public override string ToString() { - // Used by AutoCompleteBox to get text for filtering and matching - // Prefer Name, then TypeName, and fall back to base implementation - if (!string.IsNullOrEmpty(Name)) - return Name!; - if (!string.IsNullOrEmpty(TypeName)) - return TypeName!; + if (!string.IsNullOrEmpty(Name)) return Name!; + if (!string.IsNullOrEmpty(TypeName)) return TypeName!; return base.ToString(); } } \ No newline at end of file diff --git a/XSDVisualiser/Parsing/XsdSchemaParser.cs b/XSDVisualiser/Parsing/XsdSchemaParser.cs index 1e8ab54..2e46746 100644 --- a/XSDVisualiser/Parsing/XsdSchemaParser.cs +++ b/XSDVisualiser/Parsing/XsdSchemaParser.cs @@ -4,10 +4,18 @@ using System.Xml.Schema; namespace XSDVisualiser.Core; +/// +/// Parses XML Schema (XSD) into a simplified model for visualization and tooling. +/// public class XsdSchemaParser { private readonly XmlSchemaSet _set = new(); + /// + /// Reads and compiles the provided XSD file into a schema set, then produces a simplified schema model. + /// + /// Path to the XSD file. + /// A populated representing global elements and their structures. public SchemaModel Parse(string xsdPath) { _set.XmlResolver = new XmlUrlResolver(); @@ -34,8 +42,7 @@ public class XsdSchemaParser private void ValidationCallback(object? sender, ValidationEventArgs e) { - // For now, we do not throw; we capture compiled info best-effort. - // Console.Error.WriteLine($"[XSD Validation {e.Severity}] {e.Message}"); + // Intentionally no-op: schema is parsed best-effort without throwing on compile warnings/errors. } private SchemaNode BuildNodeForElement(XmlSchemaElement element, string? parentContentModel) diff --git a/XSDVisualiser/Utils/XmlValidation.cs b/XSDVisualiser/Utils/XmlValidation.cs index 84aa382..ea166a6 100644 --- a/XSDVisualiser/Utils/XmlValidation.cs +++ b/XSDVisualiser/Utils/XmlValidation.cs @@ -11,12 +11,29 @@ namespace XSDVisualiser.Core; /// public static class XmlValidator { + /// + /// Validates an XML document against the global element specified by name and optional namespace + /// from the XSD located at . + /// + /// Path to the XSD file containing the target element/type definitions. + /// The local name of the global element to validate against. + /// The namespace URI of the element; may be null to auto-detect. + /// Path to the XML file to validate. + /// Aggregated validation result with errors/warnings and diagnostics. public static XmlValidationResult ValidateAgainstElement(string xsdPath, string elementName, string? elementNamespace, string xmlPath) { var set = BuildSchemaSet(xsdPath); return ValidateAgainstElement(set, elementName, elementNamespace, xmlPath); } + /// + /// Validates an XML document against a specific global element within an already built . + /// + /// Compiled schema set to use for validation. + /// The local name of the global element to validate against. + /// The namespace URI of the element; may be null to auto-detect. + /// Path to the XML file to validate. + /// Aggregated validation result with errors/warnings and diagnostics. public static XmlValidationResult ValidateAgainstElement(XmlSchemaSet schemas, string elementName, string? elementNamespace, string xmlPath) { var result = new XmlValidationResult(); @@ -428,15 +445,31 @@ public static class XmlValidator } } +/// +/// Aggregates XML validation outcomes, including errors, warnings, and overall validity. +/// public sealed class XmlValidationResult { private readonly List _issues = new(); + /// + /// True if no validation errors have been recorded. + /// public bool IsValid => _issues.TrueForAll(i => i.Severity != XmlSeverityType.Error); + /// + /// All recorded validation issues (errors and warnings) in chronological order. + /// public IReadOnlyList Issues => _issues; + /// + /// All recorded validation errors. + /// public IEnumerable Errors => _issues.Where(i => i.Severity == XmlSeverityType.Error); + + /// + /// All recorded validation warnings. + /// public IEnumerable Warnings => _issues.Where(i => i.Severity == XmlSeverityType.Warning); internal void AddError(string message, int? line = null, int? position = null) => @@ -446,6 +479,13 @@ public sealed class XmlValidationResult _issues.Add(new XmlValidationIssue(XmlSeverityType.Warning, message, line ?? 0, position ?? 0)); } +/// +/// Represents a single validation issue (error or warning) with optional location information. +/// +/// Issue severity (Error or Warning). +/// Human-readable description of the issue. +/// Line number in the XML where the issue occurred, if available. +/// Column position in the XML where the issue occurred, if available. public sealed record XmlValidationIssue(XmlSeverityType Severity, string Message, int LineNumber, int LinePosition);