2009-09-01 3 views
2

Согласно стандартам W3C, если у вас есть nillable элемент с нулевой стоимостью, вы должны отформатировать его, как это:LinqToXml не обрабатывает nillable элементы, как и ожидалось

<myNillableElement xsi:nil="true" /> 

Но если вы используете этот LinqToXml заявление ...

element.Add(
    new XElement(ns + "myNillableElement", null); 

... полученный XML является ...

<myNillableElement /> 

... который является недействительным. И не только недействительно в соответствии с W3C, недействительным в соответствии с собственным инструментом проверки XML/XSD Microsoft. Итак, в следующий раз, когда вы проверите свой XML, вы получите ошибки.

У меня отсутствует какой-либо переключатель, который может включить правильное обращение с незаменимыми элементами?

Спасибо.

ответ

3

LINQ к XML в основном не-схемы известно - она ​​позволяет проверять дерево, но оно не получает любая конкретная семантика. Ваша ошибка в том, что null должен как-то всегда отобразиться на xsi:nil. В спецификациях W3C такого требования нет (скорее, потому что они не охватывают каких-либо языковых привязок).

В частности, XElement конструктор, который вы вызываете на самом деле принимает аргумент типа object[], который представляет собой список детей, - нет никаких причин, почему прохождение null к тому, что должно иметь какое-либо отношение к xsi:nil. В любом случае, как LINQ to XML должен знать, что вы создаете XML, который действителен в соответствии с какой-либо схемой, и что один конкретный элемент в этой схеме имеет nilled="true"?

+0

Спасибо за ваш ответ ... Думаю, я отредактирую название сообщения, потому что вы убедили меня в том, что то, что я наблюдал, - это не совсем неправильное поведение.Было бы неплохо, если бы у LinqToXml был набор классов, поддерживающий схему. – devuxer

1

Надеюсь, это не идеальный ответ, но я написал несколько методов расширения, чтобы, по крайней мере, немного облегчить работу с nillable элементами в LinqToXml.

Методы расширения:

public static class XElementExtensions 
{ 
    private static XName _nillableAttributeName = "{http://www.w3.org/2001/XMLSchema-instance}nil"; 

    public static void SetNillableElementValue(this XElement parentElement, XName elementName, object value) 
    { 
     parentElement.SetElementValue(elementName, value); 
     parentElement.Element(elementName).MakeNillable(); 
    } 

    public static XElement MakeNillable(this XElement element) 
    { 
     var hasNillableAttribute = element.Attribute(_nillableAttributeName) != null; 
     if (string.IsNullOrEmpty(element.Value)) 
     { 
      if (!hasNillableAttribute) 
       element.Add(new XAttribute(_nillableAttributeName, true)); 
     } 
     else 
     { 
      if (hasNillableAttribute) 
       element.Attribute(_nillableAttributeName).Remove(); 
     } 
     return element; 
    } 
} 

Пример использования

// "nil" attribute will be added 
element.Add(
    new XElement(NS + "myNillableElement", null) 
    .MakeNillable(); 

// no attribute will be added 
element.Add(
    new XElement(NS + "myNillableElement", "non-null string") 
    .MakeNillable(); 

// "nil" attribute will be added (if not already present) 
element.SetNillableElementValue(NS + "myNillableElement", null); 

// no attribute will be added (and will be removed if necessary) 
element.SetNillableElementValue(NS + "myNillableElement", "non-null string"); 
+0

Это будет рассматривать пустые строки как нуль, которые не могут быть желательны. То есть оба новых элемента XElement («Имя», «null») и «новый XElement (« Имя »,« ») будут отмечены как« nil ». –

+0

@MattMitchell, интересный момент, но я думаю, что я закодировал его таким образом, потому что просто невозможно представить значение нулевого элемента с помощью 'XElement'. Даже если вы выполняете 'новый XElement (name, null)', свойство 'Value' будет' string.Empty', а не 'null'. Таким образом, для строк вы теряете способность отличать нули от пустых носителей, но по крайней мере типы значений (например, 'int') работают так, как вы ожидали. Если вы можете подумать об обходном пути для строк, пожалуйста, дайте мне знать. – devuxer

+0

Хорошо для случая '.SetNillableElementValue' вы можете проверить, предоставлено ли' значение' 'null', и если так, добавьте атрибут nillable. Как вы уже сказали, после факта (например, в случае с «MakeNillable») нет способа определить, было ли значение источника равным нулю. –

2

Вы также могли бы сделать что-то вроде этого, воспользовавшись нулевым оператор коалесцирующего:

public static object Nil 
{ 
    get 
    { 
     // **I took a guess at the syntax here - you should double check.** 
     return new XAttribute(Xsi + "nil", true); 
    } 
} 

// ...... 

object nullableContent = ...; 
element.Add(
    new XElement(NS + "myNillableElement", nullableContent ?? Nil) 
    ); 
+0

Очень гладкий! Я раньше не встречался. Я думаю, что методы расширения по-прежнему необходимы для обработки 'SetElementValue', хотя, поскольку атрибут нужно либо добавить, удалить, либо оставить как есть. – devuxer

Смежные вопросы