如何在.NET中强制执行给定架构?

8

假设我有一个模式,我想让输入文档符合它。我按照以下方式根据模式加载文件:

// Load the ABC XSD
var schemata = new XmlSchemaSet();
string abcSchema = FooResources.AbcTemplate;
using (var reader = new StringReader(abcSchema))
using (var schemaReader = XmlReader.Create(reader))
{
    schemata.Add(string.Empty, schemaReader);
}

// Load the ABC file itself
var settings = new XmlReaderSettings
{
    CheckCharacters = true,
    CloseInput = false,
    ConformanceLevel = ConformanceLevel.Document,
    IgnoreComments = true,
    Schemas = schemata,
    ValidationType = ValidationType.Schema,
    ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings
};

XDocument inputDoc;
try
{
    using (var docReader = XmlReader.Create(configurationFile, settings))
    {
        inputDoc = XDocument.Load(docReader);
    }
}
catch (XmlSchemaException xsdViolation)
{
    throw new InvalidDataException(".abc file format constraint violated.", xsdViolation);
}

这种方式可以很好地检测文件中的小错误。但是,由于模式被锁定到命名空间,像下面这样的文档是无效的,但却通过了检测:

<badDoc xmlns="http://Foo/Bar/Bax">
  This is not a valid document; but Schema doesn't catch it
  because of that xmlns in the badDoc element.
</badDoc>

我想说,只有我拥有模式的命名空间才能通过模式验证。
3个回答

2

虽然看起来很傻,但您想要查看的内容实际上在 XmlReaderSettings 对象上:

settings.ValidationEventHandler += 
    (node, e) => Console.WriteLine("Bad node: {0}", node);

@codekaizen - 哈哈,说得对,那是一个“更好”的例子,尽管我仍然喜欢我的原始示例中暗示的惊奇 :) - JerKimball
同意,但可能有一些原因(例如不清除整个堆栈和解析状态),尽管由于这几乎是令人惊讶的,我希望“愚蠢”的描述词能够承担强调这种转折的全部责任。 - codekaizen
@codekaizen,你的态度非常得体,值得尊敬。 :) - JerKimball
这似乎仍然允许无效的文档通过。但至少有一个通知。不幸的是,这会导致有效的情况失败;例如,在XML中隐式定义了命名空间xml,因此文档中任何有效使用xml:space的地方都无法通过验证。 - Billy ONeal
@billy-oneal 噢,设置中还有另一个标志,可以告诉它忽略某些命名空间 - 等我回到我的桌子上,我会查一下。 - JerKimball
@BillyONeal 你好,尝试添加这个代码吧?ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings | XmlSchemaValidationFlags.AllowXmlAttributes - JerKimball

1
我最终采用的解决方案基本上是检查根节点是否处于我所期望的命名空间中。如果不是,则将其视为真正的模式验证失败处理:
// Parse the bits we need out of that file
var rootNode = inputDoc.Root;
if (!rootNode.Name.NamespaceName.Equals(string.Empty, StringComparison.Ordinal))
{
    throw new InvalidDataException(".abc file format namespace did not match.");
}

-1

1
没起作用。仍然允许无效文档通过。已相应更新示例代码。 - Billy ONeal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接