Ответ 1
Попытка решить ту же проблему. Я придумал то, что я считаю довольно чистым решением. Для ясности я пропустил некоторую проверку на входных параметрах.
Во-первых, сценарий: существует веб-служба, которая получает файл, который должен быть "правильно сформированным" xml и действителен для XSD. Конечно, мы не доверяем "хорошо fomrmness", и что это действительно против XSD, что "мы знаем" является правильным.
Код для такого метода webservice представлен ниже, я думаю, что он сам по себе.
Основной интерес представляет порядок, в котором происходит проверка, вы не проверяете пространство имен перед загрузкой, вы проверяете, но чисто.
Я решил, что могу жить с обработкой исключительных ситуаций, поскольку он ожидал, что большинство файлов будут "хорошими", и потому, что это основной способ работы (поэтому я не буду бороться с ним).
private DataTable xmlErrors;
[WebMethod]
public string Upload(byte[] f, string fileName) {
string ret = "This will have the response";
// this is the namespace that we want to use
string xmlNs = "http://mydomain.com/ns/upload.xsd";
// you could put a public url of xsd instead of a local file
string xsdFileName = Server.MapPath("~") + "//" +"shiporder.xsd";
// a simple table to store the eventual errors
// (more advanced ways possibly exist)
xmlErrors = new DataTable("XmlErrors");
xmlErrors.Columns.Add("Type");
xmlErrors.Columns.Add("Message");
try {
XmlDocument doc = new XmlDocument(); // create a document
// bind the document, namespace and xsd
doc.Schemas.Add(xmlNs, xsdFileName);
// if we wanted to validate if the XSD has itself XML errors
// doc.Schemas.ValidationEventHandler +=
// new ValidationEventHandler(Schemas_ValidationEventHandler);
// Declare the handler that will run on each error found
ValidationEventHandler xmlValidator =
new ValidationEventHandler(Xml_ValidationEventHandler);
// load the document
// will trhow XML.Exception if document is not "well formed"
doc.Load(new MemoryStream(f));
// Check if the required namespace is present
if (doc.DocumentElement.NamespaceURI == xmlNs) {
// Validate against xsd
// will call Xml_ValidationEventHandler on each error found
doc.Validate(xmlValidator);
if (xmlErrors.Rows.Count == 0) {
ret = "OK";
} else {
// return the complete error list, this is just to proove it works
ret = "File has " + xmlErrors.Rows.Count + " xml errors ";
ret += "when validated against our XSD.";
}
} else {
ret = "The xml document has incorrect or no namespace.";
}
} catch (XmlException ex) {
ret = "XML Exception: probably xml not well formed... ";
ret += "Message = " + ex.Message.ToString();
} catch (Exception ex) {
ret = "Exception: probably not XML related... "
ret += "Message = " + ex.Message.ToString();
}
return ret;
}
private void Xml_ValidationEventHandler(object sender, ValidationEventArgs e) {
xmlErrors.Rows.Add(new object[] { e.Severity, e.Message });
}
Теперь xsd будет иметь что-то вроде:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="shiporder"
targetNamespace="http://mydomain.com/ns/upload.xsd"
elementFormDefault="qualified"
xmlns="http://mydomain.com/ns/upload.xsd"
xmlns:mstns="http://mydomain.com/ns/upload.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:simpleType name="stringtype">
<xs:restriction base="xs:string"/>
</xs:simpleType>
...
</xs:schema>
И "хороший" XML будет примерно таким:
<?xml version="1.0" encoding="utf-8" ?>
<shiporder orderid="889923" xmlns="http://mydomain.com/ns/upload.xsd">
<orderperson>John Smith</orderperson>
<shipto>
<names>Ola Nordmann</names>
<address>Langgt 23</address>
Я тестировал "плохой формат XML", "недопустимый ввод в соответствии с XSD", "неправильное пространство имен".
ссылки:
Попытка избежать проверки исключений для проверки корректности
Проверка против XSD, улавливание ошибок
Интересное сообщение о проверке встроенной схемы
Привет Мартин, комментарий слишком короткий для моего ответа, поэтому я приведу его здесь, это может быть или не быть полным ответом, пусть улучшит его вместе:)
Я сделал следующие тесты:
- Тест: xmlns = "blaa"
- Результат: файл отклоняется из-за неправильного пространства имен.
- Test: xmlns = "http://mydomain.com/ns/upload.xsd" и xmlns: a = "blaa" , а элементы имеют "a: someElement"
- Результат: ошибка файла retunrs, говорящая, что он не ожидает "a: someElement"
- Test: xmlns = "http://mydomain.com/ns/upload.xsd" и xmlns: a = "blaa" , а элементы имеют "someElement" с отсутствующим отсутствующим атрибутом
- Результат: Файл возвращает ошибку, говорящую, что атрибут отсутствует
Стратегия стратегия, которой я предпочитаю, была, если документ не соответствует, затем не принимает, но дает некоторую информацию по этой причине (например,. "неправильное пространство имен" ).
Эта стратегия кажется противоречащей тому, что вы ранее говорили:
однако, если клиент пропустил декларацию пространства имен в представленном XML, я хотел бы сказать, что мы все еще можем его проверить. Я не хочу просто сказать: "Ты испортил, теперь исправь!"
В этом случае кажется, что вы можете просто игнорировать определенное пространство имен в XML. Для этого вы пропустите проверку правильного пространства имен:
...
// Don't Check if the required namespace is present
//if (doc.DocumentElement.NamespaceURI == xmlNs) {
// Validate against xsd
// will call Xml_ValidationEventHandler on each error found
doc.Validate(xmlValidator);
if (xmlErrors.Rows.Count == 0) {
ret = "OK - is valid against our XSD";
} else {
// return the complete error list, this is just to proove it works
ret = "File has " + xmlErrors.Rows.Count + " xml errors ";
ret += "when validated against our XSD.";
}
//} else {
// ret = "The xml document has incorrect or no namespace.";
//}
...
Другие идеи...
В параллельной линии мыслей, чтобы заменить предоставленное пространство имен вашим собственным, возможно, вы могли бы установить doc.DocumentElement.NamespaceURI = "mySpecialNamespace"
, заменив, таким образом, пропуски имен корневого элемента.
Ссылка: