Skip to content

feat(#7): XSD validation from game directory#50

Open
ModerRAS wants to merge 1 commit into
masterfrom
feature/issue-7-xsd-validation
Open

feat(#7): XSD validation from game directory#50
ModerRAS wants to merge 1 commit into
masterfrom
feature/issue-7-xsd-validation

Conversation

@ModerRAS

Copy link
Copy Markdown
Contributor

Summary

  • Create IXsdSchemaProvider interface
  • Implement XsdSchemaProvider for loading XSD schemas
  • Support finding XSD files in game directory
  • Validate XML files against XSD schemas
  • Add comprehensive unit tests

Changes

  • BannerlordModEditor.Common/Services/XsdSchemaProvider.cs - Implementation
  • BannerlordModEditor.Common.Tests/Services/XsdSchemaProviderTests.cs - Unit tests

Closes #7

- Create IXsdSchemaProvider interface
- Implement XsdSchemaProvider for loading XSD schemas
- Support finding XSD files in game directory
- Validate XML files against XSD schemas
- Add comprehensive unit tests

Closes #7
Copilot AI review requested due to automatic review settings March 20, 2026 01:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an XSD schema provider to locate/load game-provided XSDs and validate XML files against them, plus unit tests for basic behaviors.

Changes:

  • Introduce IXsdSchemaProvider and XsdSchemaProvider with XSD discovery, loading, and XML validation APIs
  • Implement directory scanning for XSD files under expected game folders
  • Add xUnit tests covering path discovery and missing-file cases

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
BannerlordModEditor.Common/Services/XsdSchemaProvider.cs Adds schema provider interface + implementation for locating/loading XSDs and validating XML
BannerlordModEditor.Common.Tests/Services/XsdSchemaProviderTests.cs Adds unit tests for XSD discovery/loading and validation error cases

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

{
private const string XsdDirectoryRelativePath = "XmlSchemas";
private const string ModuleDataRelativePath = "Modules";
private const string NativeModuleRelativePath = "Modules\\Native\\ModuleData";

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NativeModuleRelativePath uses Windows backslashes. When combined on non-Windows platforms, the embedded \ becomes part of the directory name, causing schema discovery/scanning to fail. Define the path using Path.Combine("Modules", "Native", "ModuleData") (or store segments and combine) so it’s platform-correct.

Suggested change
private const string NativeModuleRelativePath = "Modules\\Native\\ModuleData";
private static readonly string NativeModuleRelativePath = Path.Combine("Modules", "Native", "ModuleData");

Copilot uses AI. Check for mistakes.
{
Path.Combine(gameDirectory, XsdDirectoryRelativePath, $"{xmlFileName}.xsd"),
Path.Combine(gameDirectory, XsdDirectoryRelativePath, "Native", $"{xmlFileName}.xsd"),
Path.Combine(gameDirectory, NativeModuleRelativePath, $"{xmlFileName}.xsd")

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NativeModuleRelativePath uses Windows backslashes. When combined on non-Windows platforms, the embedded \ becomes part of the directory name, causing schema discovery/scanning to fail. Define the path using Path.Combine("Modules", "Native", "ModuleData") (or store segments and combine) so it’s platform-correct.

Copilot uses AI. Check for mistakes.
var searchPaths = new[]
{
Path.Combine(gameDirectory, XsdDirectoryRelativePath),
Path.Combine(gameDirectory, NativeModuleRelativePath)

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NativeModuleRelativePath uses Windows backslashes. When combined on non-Windows platforms, the embedded \ becomes part of the directory name, causing schema discovery/scanning to fail. Define the path using Path.Combine("Modules", "Native", "ModuleData") (or store segments and combine) so it’s platform-correct.

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +92
public XmlSchemaSet LoadSchemaSet(string xsdPath)
{
var schemaSet = new XmlSchemaSet();

if (!File.Exists(xsdPath))
return schemaSet;

try
{
using var stream = new FileStream(xsdPath, FileMode.Open, FileAccess.Read);
var schema = XmlSchema.Read(stream, null);
if (schema != null)
{
schemaSet.Add(schema);
}
}

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XmlSchemaSet can resolve <xs:include>/<xs:import> via an XmlResolver (default may allow external fetches / local file access depending on runtime), which is risky if schemas are not fully trusted. Consider setting schemaSet.XmlResolver = null (or a constrained resolver) and also ensure the XmlReaderSettings.XmlResolver is null during validation to prevent external entity/resource resolution.

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +70
try
{
xsdFiles.AddRange(Directory.GetFiles(searchPath, "*.xsd", SearchOption.AllDirectories));
}
catch
{
}

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swallowing all exceptions here can silently hide permission issues, path-too-long errors, or IO failures and make schema discovery non-deterministic in production. Catch specific exceptions (e.g., UnauthorizedAccessException, IOException) and either (a) surface them via an error list/logging, or (b) at least document why ignoring is safe and expected.

Copilot uses AI. Check for mistakes.
public class XsdSchemaProvider : IXsdSchemaProvider
{
private const string XsdDirectoryRelativePath = "XmlSchemas";
private const string ModuleDataRelativePath = "Modules";

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModuleDataRelativePath is declared but not used anywhere in this file. Removing it avoids dead code and reduces confusion about intended search paths.

Suggested change
private const string ModuleDataRelativePath = "Modules";

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +115
public bool ValidateXmlAgainstXsd(string xmlFilePath, string xsdPath, out List<string> errors)
{
errors = new List<string>();

if (!File.Exists(xmlFilePath))
{
errors.Add($"XML file not found: {xmlFilePath}");
return false;
}

if (!File.Exists(xsdPath))
{
errors.Add($"XSD schema not found: {xsdPath}");
return false;
}

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests currently cover missing XML/XSD paths, but don’t verify the core behavior of validating a real XML against a real XSD (both a passing case returning true and a failing case that returns false with populated validation errors). Adding those tests would cover the main feature this method introduces.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 自动使用骑砍2游戏内的xsd文件对配置中的xml做检查

2 participants