将 XSD 与包含一起使用

问题描述 投票:0回答:6

这是一个 XSD:

<?xml version="1.0"?>
<xsd:schema 
elementFormDefault='unqualified' 
attributeFormDefault='unqualified' 
xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
>

  <xsd:simpleType name='TheSimpleType'>
    <xsd:restriction base='xsd:string' />
  </xsd:simpleType>
</xsd:schema>

这是第二个 XSD,其中包括上面的 XSD:

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema 
elementFormDefault='unqualified' 
attributeFormDefault='unqualified' 
xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
targetNamespace='a'
xmlns='a'
>

  <xsd:include schemaLocation='Include.xsd' />

  <xsd:element name = "TheElement" >
  <xsd:complexType>
  <xsd:attribute name="Code" type="TheSimpleType" use="required"/>
  </xsd:complexType>
  </xsd:element>
</xsd:schema>

我需要将(第二个)XSD 读入 C# 中并且:

  1. 检查它是否是有效的 XSD,并且
  2. 根据它验证文件。

这里有一些需要在架构中阅读的 C# 代码:

    XmlSchemaSet schemaSet = new XmlSchemaSet();
    foreach (string sd in Schemas)
    {
        using (XmlReader r = XmlReader.Create(new FileStream(sd, FileMode.Open)))
        {
            schemaSet.Add(XmlSchema.Read(r, null));
        }
    }
    schemaSet.CompilationSettings = new XmlSchemaCompilationSettings();
    schemaSet.Compile();

.Compile() 失败,因为“类型 'a:TheSimpleType' 未声明,或者不是简单类型。”

但是,如果满足以下任一条件,它就会起作用:

  • 名称空间已从架构中删除,或者
  • 命名空间已添加到包含中。

问题是:如何让 C# 在不编辑架构的情况下接受它?

我怀疑问题在于,虽然我已将两个模式放入 XmlSchemaSet 中,但我仍然需要告诉 C# 其中一个模式包含在另一个模式中,即它本身尚未解决。事实上,如果我只告诉 XmlSchemaSet 有关主 XSD(而不是包含)(没有(或有)命名空间),那么“类型 'TheSimpleType' 未声明,或者不是简单类型。”

因此,这似乎是一个关于解决的问题,包括:如何?!

c# xml xsd xml-namespaces
6个回答
29
投票

问题在于打开架构以供在线阅读的方式:

XmlReader.Create(new FileStream(sd, FileMode.Open)

我必须编写自己的

XmlResolver
,然后才能看到包含文件的路径是如何解析的:它来自可执行文件的目录,而不是来自父模式的目录。问题在于父架构未获取其 BaseURI 集。以下是打开架构的方法:

XmlReader.Create(new FileStream(pathname, FileMode.Open, FileAccess.Read),null, pathname)

6
投票

您可以使用

XmlSchema.Includes
将它们链接在一起。然后,您只需将主模式添加到模式集中即可:

var includeSchema = XmlSchema.Read(XmlReader.Create(...), null);
var mainSchema = XmlSchema.Read(XmlReader.Create(...), null);

var include = new XmlSchemaInclude();
include.Schema = includeSchema;
mainSchema.Includes.Add(include);

var schemaSet = new XmlSchemaSet();
schemaSet.Add(mainSchema);
schemaSet.Compile();

2
投票

XmlSchemaSet 的默认行为是不尝试解析任何 XSD 包含的架构。为此,必须初始化 XmlResolver 属性。

XmlSchemaSet schemas = new XmlSchemaSet
{
    XmlResolver = new XmlUrlResolver()
};

此外,您必须按照 @Richard Barraclough 的回答为 XmlReader 设置

baseUri


1
投票

试试这个:D

public static XmlSchema LoadSchema(string pathname)
{
    XmlSchema s = null;
    XmlValidationHandler h = new XmlValidationHandler();
    using (XmlReader r = XmlReader.Create(new FileStream(pathname, FileMode.Open)))
    {
        s = XmlSchema.Read(r, new ValidationEventHandler(h.HandleValidationEvent));
    }

    if (h.Errors.Count > 0)
    {
        throw new Exception(string.Format("There were {1} errors reading the XSD at {0}. The first is: {2}.", pathname, h.Errors.Count, h.Errors[0]));
    }

    return s;
}

public static XmlSchema LoadSchemaAndResolveIncludes(string pathname)
{
    FileInfo f = new FileInfo(pathname);
    XmlSchema s = LoadSchema(f.FullName);

    foreach(XmlSchemaInclude i in s.Includes)
    {
        XmlSchema si = LoadSchema(f.Directory.FullName + @"\" + i.SchemaLocation);
        si.TargetNamespace = s.TargetNamespace;
        i.Schema = si;
    }

    return s;
}

public static List<ValidationEventArgs> Validate(string pathnameDocument, string pathnameSchema)
{
    XmlSchema s = LoadSchemaAndResolveIncludes(pathnameSchema);

    XmlValidationHandler h = new XmlValidationHandler();

    XmlDocument x = new XmlDocument();
    x.Load(pathnameDocument);
    x.Schemas.Add(s);
    s.Compile(new ValidationEventHandler(h.HandleValidationEvent));
    x.Validate(new ValidationEventHandler(h.HandleValidationEvent));
    return h.Errors;
}

特别注意

si.TargetNamespace = s.TargetNamespace;

显然,这假设包含被指定为相对于它们所包含到的模式的文件路径。


0
投票

这是我编写的用于处理 xsd 验证的方法。希望这对某人有所帮助。

        /// <summary>
        /// Ensure all xsd imported xsd documented are in same folder as master xsd
        /// </summary>
        public XsdXmlValidatorResult Validate(string xmlPath, string xsdPath, string xsdNameSpace)
        {
            var result = new XsdXmlValidatorResult();
            var readerSettings = new XmlReaderSettings {ValidationType = ValidationType.Schema};
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; 
            readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
            readerSettings.Schemas.Add(null, xsdPath);

            readerSettings.ValidationEventHandler += (sender, args) =>
                {
                    switch (args.Severity)
                    {
                        case XmlSeverityType.Warning:
                            result.Warnings.Add(args.Message);
                            break;
                        case XmlSeverityType.Error:
                            result.IsValid = false;
                            result.Warnings.Add(args.Message);
                            break;
                    }
                };

            var reader = XmlReader.Create(xmlPath, readerSettings);

            while (reader.Read()) { }

            return result;
        }

0
投票

使用.net6,代码如下 -


XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.XmlResolver = new XmlUrlResolver();     // Need this for resolving include and import
settings.ValidationType = ValidationType.Schema; // This might not be needed, I am using same settings to validate the input xml
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.Schemas.Add(null, "yourpath\\yourxsd.xsd");

settings.Schemas.Compile();

string xmlFilePath = "yourpath\\your.xml";
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);

// Create an XmlReader for the XML file
using (XmlReader reader = XmlReader.Create(xmlFilePath, settings))
{
}

想要强调的是,对于 net6,我们必须设置 settings.Schemas.XmlResolver = new XmlUrlResolver() 而不是 settings.XmlResolver = new XmlUrlResolver()

© www.soinside.com 2019 - 2024. All rights reserved.