Причина, по которой XmlSchemaValidationException.SourceObject
составляет null
, объясняется в документах
, когда во время проверки выдается XmlSchemaValidationException
Класс, который реализует интерфейс IXPathNavigable
, такой как класс XPathNavigator
или XmlNode
, объект, возвращаемый свойством SourceObject
, является экземпляром класса, который реализует интерфейс IXPathNavigable
.
КогдаXmlSchemaValidationException
генерируется во время проверки валидирующим объектом XmlReader
, значение свойства SourceObject
равно нулю.
К сожалению, XDocument
не реализуетIXPathNavigable
и, таким образом, SourceObject
, как задокументировано, null
.
Если все, что вам нужно, это SourceObject
, вы можете создать вызов Extensions.CreateNavigator(this XNode node)
, чтобы создать навигатор для документа, затем подтвердите, используя XPathNavigator.CheckValidity(XmlSchemaSet, ValidationEventHandler)
, например:
var errors = new List<XmlSchemaValidationException>();
ValidationEventHandler callback = (sender, args) =>
{
var exception = (args.Exception as XmlSchemaValidationException);
if (exception != null)
{
errors.Add(exception);
}
};
var navigator = doc.CreateNavigator();
navigator.CheckValidity(schema, callback);
foreach (var exception in errors)
{
var node = (XObject)exception.SourceObject;
// Do something with the node.
Console.WriteLine();
Console.WriteLine(exception);
Console.WriteLine("{0}: {1}", node.GetType(), node.ToString());
Assert.IsTrue(node != null, "node != null");
}
Однако эксперимент показывает, что XmlSchemaException.SourceSchemaObject
всегда кажетсябыть нулевым с этим подходом, а также XElement.IXmlSerializable.GetSchema()
не заполняется. Я не уверен, почему исходный объект схемы не передается, но тестирование в .NET Core 3.0.0 показывает, что это не так. (Возможно, это связано с , проблема # 38748: ошибки проверки XSD - отсутствуют сведения о коде ошибки схемы xsd , который был закрыт как не реализованный в настоящее время.)
Если вам нужен объект исходной схемывам также нужно будет следовать подходу из документации для Extensions.GetSchemaInfo()
и проверить XDocument
, используя XDocument.Validate(XDocument, XmlSchemaSet, ValidationEventHandler, Boolean addSchemaInfo)
. Это заполняет информацию о схеме в дереве LINQ to XML, но, к сожалению, не позволяет установить SourceObject
. Вместо этого при обнаружении ошибок вам нужно будет пройти по иерархии XElement
, ища элементы и атрибуты, для которых GetSchemaInfo()
возвращает IXmlSchemaInfo
, для которых Validity
не Valid
:
var errors = new List<XmlSchemaValidationException>();
ValidationEventHandler callback = (sender, args) =>
{
var exception = (args.Exception as XmlSchemaValidationException);
if (exception != null)
{
errors.Add(exception);
}
};
doc.Validate(schema, callback, true);
foreach (var exception in errors)
{
// Handle the exception itself.
Console.WriteLine(exception);
}
if (errors.Count > 0)
{
// If there were any errors, traverse the entire document looking for invalid nodes:
DumpInvalidNodes(doc.Root);
}
Где пример метода DumpInvalidNodes
изменен из документов Microsoft
//Taken from https://docs.microsoft.com/en-us/dotnet/api/system.xml.schema.extensions.getschemainfo?view=netframework-4.8#System_Xml_Schema_Extensions_GetSchemaInfo_System_Xml_Linq_XElement_
//with an added null check:
static void DumpInvalidNodes(XElement el)
{
if (el.GetSchemaInfo().Validity != XmlSchemaValidity.Valid)
Console.WriteLine("Invalid Element {0}",
el.AncestorsAndSelf()
.InDocumentOrder()
.Aggregate("", (s, i) => s + "/" + i.Name.ToString()));
foreach (XAttribute att in el.Attributes())
{
var si = att.GetSchemaInfo();
// MUST CHECK FOR NULL HERE
// Because w3 standard attributes like xmlns:xsi will have null SchemaInfo
// when not included in the schema, rather than being reported as Invalid.
if (si != null && si.Validity != XmlSchemaValidity.Valid)
Console.WriteLine("Invalid Attribute {0}",
att
.Parent
.AncestorsAndSelf()
.InDocumentOrder()
.Aggregate("",
(s, i) => s + "/" + i.Name.ToString()) + "/@" + att.Name.ToString()
);
}
foreach (XElement child in el.Elements())
DumpInvalidNodes(child);
}
Обратите внимание, что мое тестирование показало, что код документации необходимо изменить, чтобы проверить, не вернул ли XAttribute.GetSchemaInfo()
1085 *. Похоже, это происходит для стандартных атрибутов w3c, таких как xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
, когда они явно не включены в схему.
Демо-скрипта # 2 здесь .
Обновление : похоже, doc.CreateNavigator().CheckValidity(schema, callback)
не работает в более ранних версиях Full Framework;например, в .Net 4.7 выдается исключение System.NotSupportedException: This XPathNavigator does not support XSD validation
. Демонстрационная скрипка № 3 здесь . Если вы столкнулись с этой проблемой, вам придется использовать второй подход.