«Префикс пространства имен не определен», когда он на самом деле определен - PullRequest
2 голосов
/ 14 января 2011

У меня проблемы с десериализацией XML с "неопределенным" префиксом пространства имен, который действительно определен.

Мы опубликовали внутренний веб-сервис на C #, который обслуживает множество клиентов. IDE нового клиента настаивает на объявлении xsi: type для каждого элемента в своем выводе XML, и они не могут отключить эту «функцию».

XML-сообщение, которое они создают, выглядит следующим образом, где «пространство имен» - это правильное пространство имен.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
  <myOperation xsi:type="ns1:namespace" xmlns="namespace" xmlns:ns1="namespace">
    <inputString xsi:type="xsd:string">ABCDEF</inputString>
    <books xsi:type="ns1:booksType">
      <bookID xsi:type="xsd:string">ABC123</bookID>
      <bookID xsi:type="xsd:string">DEF456</bookID>
    </books>
    <!-- ... snip... -->
  </myOperation>
</soapenv:Body>

<books> - это в основном массив строк.

Метод службы принимает как XmlNode, но XmlSerializer выдает ошибку «префикс« ns1 »не определен». (Он определен в родительском узле, но, видимо, этого недостаточно.) У меня похожая проблема с использованием wsdl.exe для генерации классов и десериализации ввода для меня.

Использование XmlNamespaceManager для указания префиксов не кажется правильным - похоже на магические числа, и я не могу предсказать, какой префикс в любом случае объявит данный потребитель. Есть ли способ справиться с этим, не удаляя атрибуты (books.Attributes.RemoveAll)? Это тоже не особенно элегантно.

Я обнаружил, что books.OuterXML не содержит никакой информации для 'ns1', если только я не взломал входящий элемент, чтобы использовать этот префикс (), поэтому я могу понять, почему он жалуется, но я пока не понимаю, почему ' ns1 'не распознается из предыдущего определения выше.

Большое спасибо за любую помощь или, по крайней мере, образование, которое кто-то может предоставить.

Редактирует: все работает нормально, если я изменяю <books> на префикс, т.е. <ns1:books xsi:type="ns1:booksType">. Это работает независимо от того, определил я xmlns или нет. Это может быть согласовано с этим ответом , но я до сих пор не понимаю, как я мог бы реально объявить префикс в служебном коде.

@ Крис, конечно. Надеюсь, я смогу найти баланс между «скупым с закрытым исходным кодом» и «пригодным для тех, кто поможет». Здесь "books" - это XmlNode, полученный в параметре метода сервиса. (Не выходить за рамки темы, но также смиренно приму предложения по ее улучшению в целом; я все еще новичок.)

XmlSerializer xmlSerializer = new XmlSerializer(typeof(booksType));
StringReader xmlDataReader = new StringReader(books.OuterXml);
books = (booksType)xmlSerializer.Deserialize(xmlDataReader);

Класс в значительной степени такой:

[Serializable()]
[XmlRoot("books", Namespace = "namespace")]
[XmlTypeAttribute(TypeName = "booksType", Namespace = "namespace")]
public class booksType
{
    [XmlElement(ElementName = "bookID")]
    public string[] bookIDs { get; set; }
}

1 Ответ

2 голосов
/ 14 января 2011

Ваш код десериализации может выглядеть примерно так:

    XmlSerializer sz = new XmlSerializer(typeof(booksType));
    var reader = new XmlNodeReader(booksXmlNode);
    var books = sz.Deserialize(reader);

[EDIT] Это лучше, потому что объявления пространства имен сохраняются с XmlNode, тогда как преобразование в строку XML через OuterXml, по-видимому, отрезает объявление пространства имен для префикса ns1, и сериализатор затем блокирует значение атрибута типа содержащий этот префикс. Я полагаю, что это ошибка в реализации XML, но, возможно, гуру XML может это подтвердить.

Это должно помочь вам справиться с ошибкой, которую вы видите, но я не уверен, решит ли она проблему полностью.

[ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ] Как отмечено в комментариях ниже, в .NET XmlSerializer есть ошибка, которая приводит к сбою десериализации. Проходя по коду десериализации в сгенерированной сборке, есть точка, в которой проверяется следующее условие:

(object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_namespace)) 

Хотя свойство Namespace XmlQualifiedName имеет то же значение («пространство имен»), что и строковая переменная id2_namespace, условие оценивается как ложное, поскольку оно закодировано как тест идентификации объекта, а не как тест для эквивалентности строковых значений. Несоблюдение этого условия ведет непосредственно к исключению, о котором сообщает OP.

Насколько я вижу, эта ошибка всегда приводит к сбою десериализации, когда XML для десериализуемого объекта использует один префикс в имени корневого элемента объекта и другой префикс (определенный как то же пространство имен) в xsi этого элемента : атрибут типа.

...