Did some cleanup of the UI and code

This commit is contained in:
Frederik Jacobsen 2025-10-18 19:47:22 +02:00
parent 8fd2b05b4d
commit 14bad15f4a
7 changed files with 198 additions and 219 deletions

View File

@ -9,13 +9,11 @@ namespace XSDVisualiser.Desktop.Converters
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is Occurs occ)
{
var min = occ.Min;
var max = occ.MaxIsUnbounded ? "*" : occ.Max.ToString(culture);
return $"[{min}..{max}]";
}
return null;
if (value is not Occurs occ) return null;
var min = occ.Min;
var max = occ.MaxIsUnbounded ? "*" : occ.Max.ToString(culture);
return $"[{min}..{max}]";
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)

View File

@ -19,7 +19,7 @@
</DockPanel>
<!-- Body: left tree | splitter | right details -->
<Grid Grid.Row="1" ColumnDefinitions="*,Auto,1.6*" RowDefinitions="*">
<Grid Grid.Row="1" ColumnDefinitions="2*,Auto,*" RowDefinitions="*">
<!-- Left: Tree -->
<Border Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource PanelBorderBrush}"
@ -30,11 +30,8 @@
<TreeDataTemplate DataType="{x:Type m:SchemaNode}" ItemsSource="{Binding Children}">
<StackPanel>
<!-- Connector line from parent to this node (hidden for roots where ContentModel is null) -->
<Grid Margin="0,6,0,2" IsVisible="{Binding ContentModel, Converter={x:Static ObjectConverters.IsNotNull}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Margin="0,8,8,2" IsVisible="{Binding ContentModel, Converter={x:Static ObjectConverters.IsNotNull}}"
ColumnDefinitions="16,*">
<!-- leading small elbow -->
<Rectangle Grid.Column="0" Width="16" Height="2" Fill="{DynamicResource SeparatorBrush}" VerticalAlignment="Center"/>
<Grid Grid.Column="1">
@ -50,7 +47,7 @@
<Border CornerRadius="4"
BorderBrush="{Binding Cardinality, Converter={StaticResource OptionalToBrush}}"
BorderThickness="{Binding Cardinality, Converter={StaticResource OptionalToThickness}}"
Padding="8" Margin="0,0,0,6" Background="{DynamicResource PanelBackgroundBrush}">
Padding="8" Margin="0,0,8,6" Background="{DynamicResource PanelBackgroundBrush}">
<StackPanel Orientation="Vertical" Spacing="2">
<!-- Name on its own line, prominent -->
<TextBlock Text="{Binding Name}" FontWeight="SemiBold"/>
@ -69,7 +66,7 @@
<!-- Optional: show content model as a subtle hint -->
<TextBlock Text="{Binding ContentModel, StringFormat=Model: {0}}"
Foreground="{DynamicResource MutedTextBrush}"/>
Foreground="{DynamicResource SubtleTextBrush}" FontWeight="SemiBold"/>
</StackPanel>
</Border>
</StackPanel>
@ -95,116 +92,31 @@
<!-- General info -->
<Border BorderBrush="{DynamicResource PanelBorderBrush}" BorderThickness="1" CornerRadius="4" Padding="10">
<Grid ColumnDefinitions="Auto,*,Auto,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock Text="Name:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Margin="8,0,0,0" Text="{Binding Name}"/>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" FontWeight="Bold"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="8,0,0,0" Text="{Binding Name}"/>
<TextBlock Grid.Row="1" Text="Type:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="1" Margin="8,0,0,0" Text="{Binding TypeName}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Built-in:" FontWeight="Bold"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="8,0,0,0" Text="{Binding BuiltInType}" FontWeight="Bold"/>
<TextBlock Grid.Row="2" Text="Built-in:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="2" Margin="8,0,0,0" Text="{Binding BuiltInType}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Model:" FontWeight="Bold"/>
<TextBlock Grid.Row="2" Grid.Column="1" Margin="8,0,0,0" Text="{Binding ContentModel}"/>
<TextBlock Grid.Row="3" Text="Namespace:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="3" Margin="8,0,0,0" Text="{Binding Namespace}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Namespace:" FontWeight="Bold"/>
<TextBlock Grid.Row="3" Grid.Column="1" Margin="8,0,0,0" Text="{Binding Namespace}"/>
<TextBlock Grid.Row="4" Text="Cardinality:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="4" Margin="8,0,0,0" Text="{Binding Cardinality, Converter={StaticResource CardinalityToLabel}}"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="Cardinality:" FontWeight="Bold"/>
<TextBlock Grid.Row="4" Grid.Column="1" Margin="8,0,0,0" Text="{Binding Cardinality, Converter={StaticResource CardinalityToLabel}}"/>
<TextBlock Grid.Column="2" Text="Model:" FontWeight="Bold"/>
<TextBlock Grid.Column="3" Margin="8,0,0,0" Text="{Binding ContentModel}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="Nillable:" FontWeight="Bold"/>
<TextBlock Grid.Row="5" Grid.Column="1" Margin="8,0,0,0" Text="{Binding IsNillable}"/>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Type:" FontWeight="Bold"/>
<TextBlock Grid.Row="6" Grid.Column="1" Margin="8,0,0,0" Text="{Binding TypeName}"/>
<TextBlock Grid.Row="5" Text="Nillable:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="5" Margin="8,0,0,0" Text="{Binding IsNillable}"/>
</Grid>
</Border>
<!-- Attributes -->
<StackPanel>
<TextBlock Text="Attributes" FontWeight="SemiBold"/>
<ItemsControl ItemsSource="{Binding Attributes}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="m:AttributeInfo">
<Border BorderBrush="{DynamicResource PanelBorderBrush}" BorderThickness="1" CornerRadius="4" Padding="8" Margin="0,6,0,0">
<StackPanel Spacing="8">
<Grid ColumnDefinitions="Auto,*,Auto,*" RowDefinitions="Auto,Auto,Auto">
<TextBlock Text="Name:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Margin="8,0,0,0" Text="{Binding Name}"/>
<TextBlock Grid.Row="1" Text="Use:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="1" Margin="8,0,0,0" Text="{Binding Use}"/>
<TextBlock Grid.Row="2" Text="Type:" FontWeight="Bold"/>
<TextBlock Grid.Column="1" Grid.Row="2" Margin="8,0,0,0" Text="{Binding TypeName}"/>
<TextBlock Grid.Column="2" Text="Built-in:" FontWeight="Bold"/>
<TextBlock Grid.Column="3" Margin="8,0,0,0" Text="{Binding BuiltInType}"/>
</Grid>
<StackPanel IsVisible="{Binding Constraints, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Constraints" FontWeight="SemiBold"/>
<StackPanel>
<TextBlock Text="Enumerations" FontWeight="SemiBold"/>
<ItemsControl ItemsSource="{Binding Constraints.Enumerations}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{Binding ., StringFormat=• {0}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<StackPanel>
<TextBlock Text="Patterns" FontWeight="SemiBold"/>
<ItemsControl ItemsSource="{Binding Constraints.Patterns}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="x:String">
<TextBlock Text="{Binding ., StringFormat=• {0}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<StackPanel IsVisible="{Binding Constraints.Numeric, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Numeric bounds" FontWeight="SemiBold"/>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Numeric.MinInclusive, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Min inclusive:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Numeric.MinInclusive}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Numeric.MaxInclusive, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Max inclusive:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Numeric.MaxInclusive}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Numeric.MinExclusive, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Min exclusive:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Numeric.MinExclusive}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Numeric.MaxExclusive, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Max exclusive:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Numeric.MaxExclusive}"/>
</StackPanel>
</StackPanel>
<StackPanel IsVisible="{Binding Constraints.Length, Converter={x:Static ObjectConverters.IsNotNull}}">
<TextBlock Text="Length bounds" FontWeight="SemiBold"/>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Length.LengthSpecified}">
<TextBlock Text="Length:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Length.Length}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Length.MinLengthSpecified}">
<TextBlock Text="Min length:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Length.MinLength}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding Constraints.Length.MaxLengthSpecified}">
<TextBlock Text="Max length:" FontWeight="Bold"/>
<TextBlock Margin="8,0,0,0" Text="{Binding Constraints.Length.MaxLength}"/>
</StackPanel>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
<!-- Constraints -->
<StackPanel>
<TextBlock Text="Constraints" FontWeight="SemiBold"/>

View File

@ -3,8 +3,8 @@ using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using XSDVisualiser.Core;
using XSDVisualiser.Models;
using XSDVisualiser.Parsing;
namespace XSDVisualiser.Desktop
{

View File

@ -12,7 +12,7 @@ namespace XSDVisualiser.Desktop
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
public static AppBuilder BuildAvaloniaApp() =>
private static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace()

View File

@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using XSDVisualiser.Models;
namespace XSDVisualiser.Parsing
namespace XSDVisualiser.Core
{
public class XsdSchemaParser
{
@ -16,16 +13,16 @@ namespace XSDVisualiser.Parsing
_set.XmlResolver = new XmlUrlResolver();
using var reader = XmlReader.Create(xsdPath, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore });
var schema = XmlSchema.Read(reader, ValidationCallback);
_set.Add(schema);
_set.Add(schema!);
_set.CompilationSettings = new XmlSchemaCompilationSettings { EnableUpaCheck = true };
_set.Compile();
var model = new SchemaModel
{
TargetNamespace = schema.TargetNamespace
TargetNamespace = schema!.TargetNamespace
};
foreach (XmlSchemaElement globalEl in _set.Schemas().Cast<XmlSchema>()
foreach (var globalEl in _set.Schemas().Cast<XmlSchema>()
.SelectMany(s => s.Elements.Values.Cast<XmlSchemaElement>()))
{
var node = BuildNodeForElement(globalEl, parentContentModel: null);
@ -58,24 +55,22 @@ namespace XSDVisualiser.Parsing
};
var type = ResolveElementType(element);
if (type != null)
if (type == null) return node;
node.TypeName = GetQualifiedTypeName(type);
if (type.Datatype != null)
{
node.TypeName = GetQualifiedTypeName(type);
if (type.Datatype != null)
{
node.BuiltInType = type.Datatype.TypeCode.ToString();
}
node.BuiltInType = type.Datatype.TypeCode.ToString();
}
switch (type)
{
case XmlSchemaComplexType ct:
HandleComplexType(node, ct);
break;
case XmlSchemaSimpleType st:
node.ContentModel = "simple";
node.Constraints = ExtractConstraints(st);
break;
}
switch (type)
{
case XmlSchemaComplexType ct:
HandleComplexType(node, ct);
break;
case XmlSchemaSimpleType st:
node.ContentModel = "simple";
node.Constraints = ExtractConstraints(st);
break;
}
return node;
@ -84,7 +79,7 @@ namespace XSDVisualiser.Parsing
private static string? GetQualifiedTypeName(XmlSchemaType type)
{
if (!type.QualifiedName.IsEmpty) return type.QualifiedName.ToString();
return type.BaseXmlSchemaType != null && !type.BaseXmlSchemaType.QualifiedName.IsEmpty
return type.BaseXmlSchemaType is { QualifiedName.IsEmpty: false }
? type.BaseXmlSchemaType.QualifiedName.ToString()
: type.Name;
}
@ -96,16 +91,71 @@ namespace XSDVisualiser.Parsing
{
return _set.GlobalTypes[el.SchemaTypeName] as XmlSchemaType;
}
if (el.SchemaType != null) return el.SchemaType;
return null;
return el.SchemaType;
}
private void HandleComplexType(SchemaNode node, XmlSchemaComplexType ct)
{
// Attributes
foreach (XmlSchemaAttribute attr in ct.AttributeUses.Values.OfType<XmlSchemaAttribute>())
// Collect attributes (ensure uniqueness)
var seenAttrKeys = new HashSet<string>(StringComparer.Ordinal);
// 1) Compiled attribute uses (includes inherited/group attributes after Compile)
foreach (var attr in ct.AttributeUses.Values.OfType<XmlSchemaAttribute>())
{
node.Attributes.Add(ExtractAttribute(attr));
var qn = attr.QualifiedName.IsEmpty ? attr.RefName : attr.QualifiedName;
var key = qn.ToString();
if (seenAttrKeys.Add(key))
{
node.Attributes.Add(ExtractAttribute(attr));
}
}
// 2) Uncompiled attributes directly on the type (fallback)
foreach (var a in ct.Attributes.OfType<XmlSchemaAttribute>())
{
var qn = a.QualifiedName.IsEmpty ? a.RefName : a.QualifiedName;
var key = qn.ToString();
if (seenAttrKeys.Add(key))
{
node.Attributes.Add(ExtractAttribute(a));
}
}
// 3) Attributes from complexContent extension/restriction
if (ct.ContentModel is XmlSchemaComplexContent cc)
{
switch (cc.Content)
{
case XmlSchemaComplexContentExtension cext:
{
foreach (var a in cext.Attributes.OfType<XmlSchemaAttribute>())
{
var qn = a.QualifiedName.IsEmpty ? a.RefName : a.QualifiedName;
var key = qn.ToString();
if (seenAttrKeys.Add(key))
{
node.Attributes.Add(ExtractAttribute(a));
}
}
break;
}
case XmlSchemaComplexContentRestriction cres:
{
foreach (var a in cres.Attributes.OfType<XmlSchemaAttribute>())
{
var qn = a.QualifiedName.IsEmpty ? a.RefName : a.QualifiedName;
var key = qn.ToString();
if (seenAttrKeys.Add(key))
{
node.Attributes.Add(ExtractAttribute(a));
}
}
break;
}
}
}
// Content model
@ -158,31 +208,43 @@ namespace XSDVisualiser.Parsing
else if (ct.ContentType == XmlSchemaContentType.TextOnly && ct.ContentModel is XmlSchemaSimpleContent simpleContent)
{
node.ContentModel = "simple";
if (simpleContent.Content is XmlSchemaSimpleContentExtension ext)
switch (simpleContent.Content)
{
var baseType = ResolveType(ext.BaseTypeName);
if (baseType is XmlSchemaSimpleType st)
case XmlSchemaSimpleContentExtension ext:
{
node.Constraints = ExtractConstraints(st);
node.TypeName ??= GetQualifiedTypeName(st);
node.BuiltInType ??= st.Datatype?.TypeCode.ToString();
}
var baseType = ResolveType(ext.BaseTypeName);
if (baseType is XmlSchemaSimpleType st)
{
node.Constraints = ExtractConstraints(st);
node.TypeName ??= GetQualifiedTypeName(st);
node.BuiltInType ??= st.Datatype?.TypeCode.ToString();
}
foreach (XmlSchemaAttribute attr in ext.Attributes.OfType<XmlSchemaAttribute>())
{
node.Attributes.Add(ExtractAttribute(attr));
foreach (var attr in ext.Attributes.OfType<XmlSchemaAttribute>())
{
var qn = attr.QualifiedName.IsEmpty ? attr.RefName : attr.QualifiedName;
var key = qn.ToString();
if (seenAttrKeys.Add(key))
{
node.Attributes.Add(ExtractAttribute(attr));
}
}
break;
}
}
else if (simpleContent.Content is XmlSchemaSimpleContentRestriction res)
{
var baseType = ResolveType(res.BaseTypeName);
if (baseType is XmlSchemaSimpleType st)
case XmlSchemaSimpleContentRestriction res:
{
var cons = ExtractConstraints(st);
MergeFacets(cons, res.Facets);
node.Constraints = cons;
node.TypeName ??= GetQualifiedTypeName(st);
node.BuiltInType ??= st.Datatype?.TypeCode.ToString();
var baseType = ResolveType(res.BaseTypeName);
if (baseType is XmlSchemaSimpleType st)
{
var cons = ExtractConstraints(st);
MergeFacets(cons, res.Facets);
node.Constraints = cons;
node.TypeName ??= GetQualifiedTypeName(st);
node.BuiltInType ??= st.Datatype?.TypeCode.ToString();
}
break;
}
}
}
@ -208,12 +270,10 @@ namespace XSDVisualiser.Parsing
else if (!attr.SchemaTypeName.IsEmpty) st = ResolveType(attr.SchemaTypeName) as XmlSchemaSimpleType;
else if (attr.SchemaType != null) st = attr.SchemaType;
if (st != null)
{
info.TypeName = GetQualifiedTypeName(st);
info.BuiltInType = st.Datatype?.TypeCode.ToString();
info.Constraints = ExtractConstraints(st);
}
if (st == null) return info;
info.TypeName = GetQualifiedTypeName(st);
info.BuiltInType = st.Datatype?.TypeCode.ToString();
info.Constraints = ExtractConstraints(st);
return info;
}
@ -225,33 +285,39 @@ namespace XSDVisualiser.Parsing
BaseTypeName = GetQualifiedTypeName(st.BaseXmlSchemaType)
};
if (st.Content is XmlSchemaSimpleTypeRestriction restr)
switch (st.Content)
{
MergeFacets(cons, restr.Facets);
}
else if (st.Content is XmlSchemaSimpleTypeList list)
{
cons.Patterns.Add("(list)");
if (!list.ItemTypeName.IsEmpty)
case XmlSchemaSimpleTypeRestriction restr:
MergeFacets(cons, restr.Facets);
break;
case XmlSchemaSimpleTypeList list:
{
var baseType = ResolveType(list.ItemTypeName);
if (baseType is XmlSchemaSimpleType itemSt)
cons.Patterns.Add("(list)");
if (!list.ItemTypeName.IsEmpty)
{
var sub = ExtractConstraints(itemSt);
Merge(cons, sub);
var baseType = ResolveType(list.ItemTypeName);
if (baseType is XmlSchemaSimpleType itemSt)
{
var sub = ExtractConstraints(itemSt);
Merge(cons, sub);
}
}
break;
}
}
else if (st.Content is XmlSchemaSimpleTypeUnion union)
{
cons.Patterns.Add("(union)");
foreach (var memberType in union.BaseMemberTypes)
case XmlSchemaSimpleTypeUnion union:
{
if (memberType is XmlSchemaSimpleType mst)
cons.Patterns.Add("(union)");
foreach (var memberType in union.BaseMemberTypes)
{
var sub = ExtractConstraints(mst);
Merge(cons, sub);
if (memberType is { } mst)
{
var sub = ExtractConstraints(mst);
Merge(cons, sub);
}
}
break;
}
}
@ -261,8 +327,8 @@ namespace XSDVisualiser.Parsing
private static void Merge(ConstraintSet target, ConstraintSet? source)
{
if (source == null) return;
foreach (var e in source.Enumerations) if (!target.Enumerations.Contains(e)) target.Enumerations.Add(e);
foreach (var p in source.Patterns) if (!target.Patterns.Contains(p)) target.Patterns.Add(p);
foreach (var e in source.Enumerations.Where(e => !target.Enumerations.Contains(e))) target.Enumerations.Add(e);
foreach (var p in source.Patterns.Where(p => !target.Patterns.Contains(p))) target.Patterns.Add(p);
if (source.Numeric != null)
{
target.Numeric ??= new NumericBounds();
@ -271,25 +337,25 @@ namespace XSDVisualiser.Parsing
target.Numeric.MinExclusive ??= source.Numeric.MinExclusive;
target.Numeric.MaxExclusive ??= source.Numeric.MaxExclusive;
}
if (source.Length != null)
if (source.Length == null) return;
target.Length ??= new LengthBounds();
if (source.Length.LengthSpecified && !target.Length.LengthSpecified)
{
target.Length ??= new LengthBounds();
if (source.Length.LengthSpecified && !target.Length.LengthSpecified)
{
target.Length.Length = source.Length.Length;
target.Length.LengthSpecified = true;
}
if (source.Length.MinLengthSpecified && !target.Length.MinLengthSpecified)
{
target.Length.MinLength = source.Length.MinLength;
target.Length.MinLengthSpecified = true;
}
if (source.Length.MaxLengthSpecified && !target.Length.MaxLengthSpecified)
{
target.Length.MaxLength = source.Length.MaxLength;
target.Length.MaxLengthSpecified = true;
}
target.Length.Length = source.Length.Length;
target.Length.LengthSpecified = true;
}
if (source.Length.MinLengthSpecified && !target.Length.MinLengthSpecified)
{
target.Length.MinLength = source.Length.MinLength;
target.Length.MinLengthSpecified = true;
}
if (!source.Length.MaxLengthSpecified || target.Length.MaxLengthSpecified) return;
target.Length.MaxLength = source.Length.MaxLength;
target.Length.MaxLengthSpecified = true;
}
private static void MergeFacets(ConstraintSet cons, XmlSchemaObjectCollection facets)

View File

@ -1,4 +1,4 @@
using XSDVisualiser.Parsing;
using XSDVisualiser.Core;
using XSDVisualiser.Utils;
/*
@ -80,6 +80,8 @@ catch (Exception ex)
Environment.Exit(3);
}
return;
static void PrintHelp()
{
Console.WriteLine("XSDVisualiser - Parse an XSD and emit a structural model with types, constraints, and cardinality");

View File

@ -8,6 +8,12 @@ namespace XSDVisualiser.Utils
{
public static class Serialization
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};
public static string ToXml<T>(T obj)
{
var serializer = new XmlSerializer(typeof(T));
@ -20,12 +26,7 @@ namespace XSDVisualiser.Utils
public static string ToJson<T>(T obj)
{
var options = new JsonSerializerOptions
{
WriteIndented = true,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};
return JsonSerializer.Serialize(obj, options);
return JsonSerializer.Serialize(obj, JsonOptions);
}
private sealed class Utf8StringWriter : StringWriter