Как использовать сложные типы с xs:any / ##any и смешанный код, сгенерированный инструментом XSD

У меня есть следующий сложный тип в моей XML-схеме:

<xs:complexType name="Widget" mixed="true">
    <xs:sequence>
        <xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>

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

Когда я запускаю это через .NET XSD Tool, я получаю следующий код генерации:

public partial class Widget{

    private System.Xml.XmlNode[] anyField;

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    [System.Xml.Serialization.XmlAnyElementAttribute()]
    public System.Xml.XmlNode[] Any {
        get {
            return this.anyField;
        }
        set {
            this.anyField = value;
        }
    }
}

Вопрос, который у меня есть, заключается в том, что я не совсем уверен, как мне это использовать. В конечном итоге мне нужно иметь возможность установить значение виджета либо:

<widget>Hello World!</widget>

or

<widget>
  <foo>Hello World</foo>
</widget>

Оба из которых проверяют схему


person MrEyes    schedule 11.02.2011    source источник


Ответы (2)


За это:

<widget>  
    <foo>Hello World</foo>
</widget>

Использовать этот:

XmlDocument dom = new XmlDocument();
Widget xmlWidget = new Widget();
xmlWidget.Any = new XmlNode[1];
xmlWidget.Any[0] = dom.CreateNode(XmlNodeType.Element, "foo", dom.NamespaceURI);
xmlWidget.Any[0].InnerText = "Hello World!";

За это:

<widget>Hello World!</widget>

Использовать этот:

XmlDocument dom = new XmlDocument();
XmlNode node = dom.CreateNode(XmlNodeType.Element, "foo", dom.NamespaceURI);
node.InnerText = "Hello World";

Widget w = new Widget();
w.Any = new XmlNode[1];
w.Any[0] = node.FirstChild; 
person pmartin    schedule 11.02.2011
comment
Это не сработает, вы не инициализировали xmlWidget.Any[0]. Таким образом, это вызовет исключение нулевой ссылки - person MrEyes; 12.02.2011
comment
Я обновил свой ответ, чтобы справиться с NullReferenceExceptions. Однако я не уверен, что вы сможете выполнить опцию только для внутреннего текста. сделать это в коде означало бы, что класс Widget может функционировать как как строковый тип, так и как массив узлов. Я не верю, что это возможно со стандартным поколением XSD. - person pmartin; 12.02.2011
comment
Я сделал правку, которая очень похожа на код, который вы разместили. Я не уверен, что вы найдете другой способ сделать это. На самом деле вы пытаетесь переопределить свойство Widget. В одном случае вы хотите, чтобы это была просто строка, а в других случаях вам нужен массив узлов, но вы не можете определить свойство с одним и тем же именем несколько раз в одном классе. - person pmartin; 12.02.2011
comment
Чтобы быть более явным (и показать намерения вашего кода), вы можете заменить вызов node.FirstChild на dom.CreateTextNode(Hello World). - person an phu; 12.05.2016

Опубликовать это как ответ, поскольку технически это работает и отвечает на вопрос. Однако это похоже на действительно неприятный взлом. Так что, если у кого-то есть альтернативное и лучшее решение, я все слушаю.

string mystring= "if I check this code in it will at least have comedy value";

XmlDocument thisLooksBad = new XmlDocument();
thisLooksBad.LoadXml("<temp>" + mystring + "</temp>");

Widget stringWidget = new Widget();
stringWidget.Any = new XmlNode[1];
stringWidget.Any[0] = thisLooksBad.SelectSingleNode("/temp").FirstChild;

Как вы можете видеть, я помещаю свою строку в XmlDocument, завернутый в теги, это работает, компилируется и сериализуется без проблем - так что да, это решение, но мне кажется, что это неприятный хак.

string myxml = "<x><y>something</y></x>";

XmlDocument thisDoesntLookSoBad = new XmlDocument();
thisLooksBad.LoadXml(myxml);

Widget xmlWidget = new Widget();
xmlWidget.Any = new XmlNode[1];
xmlWidget.Any[0] = thisDoesntLookSoBad;

В этом примере я помещаю свой XML в XmlDocument, а затем назначаю его сгенерированному классу. Это имеет больше смысла, поскольку я работаю с XML, а не с необработанной строкой.

Любопытно, что я также могу сделать это, и это тоже работает (но тоже неприятный хак):

string myxml = "<x><y>something</y></x>";

XmlDocument dom = new XmlDocument();
dom.LoadXml("<temp>" + myxml + "</temp>");

Widget xmlWidget = new Widget();
xmlWidget.Any = new XmlNode[1];
xmlWidget.Any[0] = dom.SelectSingleNode("/temp").FirstChild;
person MrEyes    schedule 11.02.2011
comment
Какой из этих примеров удовлетворяет требованию <widget>Hello World!</widget>. - person pmartin; 12.02.2011
comment
Первый образец десериализуется в: ‹widget›, если я проверю, что этот код в нем будет, по крайней мере, иметь комедийное значение‹/widget› - person MrEyes; 12.02.2011
comment
Как вы говорите, это выполняет свою работу, но я предпочитаю решение pmartin, потому что оно более надежно, т.е. не использует конкатенацию строк для построения Xml DOM. - person an phu; 12.05.2016