Обойти указанный c родительский узел при десериализации XML? - PullRequest
2 голосов
/ 29 января 2020

Предполагая следующее XML:

<A>
    <B>
        <B1>b1Value</B1>
        <B2>b2Value</B2>
        <B3>b3Value</B3>
    </B>
    <C Attr="val1"/>
    <C Attr="val2"/>
    <C Attr="val3"/>
</A>

И следующие желаемые классы десериализации:

public class C
{
    [XmlAttribute]
    public string Attr { get; set; }
}

[XmlRoot]
public class A
{
    [XmlElement("C")]
    public C[] Cs { get; set; }
    public string B1 { get; set; }
    public string B2 { get; set; }
    public string B3 { get; set; }
}

Как я могу десериализовать XML, чтобы мой класс А мог иметь свойства B1, B2 и B3 без родительского свойства B?

Когда я использую этот код:

string xml =
@"<A>
    <B>
        <B1>b1Value</B1>
        <B2>b2Value</B2>
        <B3>b3Value</B3>
    </B>
    <C Attr=""val1""/>
    <C Attr=""val2""/>
    <C Attr=""val3""/>
</A>";

XmlSerializer serializer = new XmlSerializer(typeof(A));
A a;

using (TextReader reader = new StringReader(xml))
{
    a = serializer.Deserialize(reader) as A;
}

все свойства BX пусты.

dotnetfiddle здесь ,

Спасибо.

Ответы [ 3 ]

2 голосов
/ 29 января 2020

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

public class C
{
    [XmlAttribute]
    public string Attr { get; set; }
}
public class B
{
    [XmlElement]
    public string B1 { get; set; }
    [XmlElement]
    public string B2 { get; set; }
    [XmlElement]
    public string B3 { get; set; }
}
[XmlRoot]
public class A
{
    [XmlElement("C")]
    public C[] Cs { get; set; }
    [XmlElement("B")]
    public B B { get; set; }

    [XmlIgnore()]
    public string B1 => B?.B1;
    [XmlIgnore()]
    public string B2 => B?.B2;
    [XmlIgnore()]
    public string B3 => B?.B3;
}

dotnetfiddle

1 голос
/ 29 января 2020

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

Вы не можете десериализовать xml, который у вас есть, без использования B в качестве родительского класса. Поскольку B1, B2 и B3 являются частью элемента B, вы должны использовать структуру в вашем C#, чтобы соответствовать ей. Каждый элемент, который вы имеете в элементе B, также имеет разные имена.

public class C
{
    [XmlAttribute]
    public string Attr { get; set; }
}
public class B
{
    [XmlElement]
    public string B1 { get; set; }
    [XmlElement]
    public string B2 { get; set; }
    [XmlElement]
    public string B3 { get; set; }
}
[XmlRoot]
public class A
{
    [XmlElement("C")]
    public C[] Cs { get; set; }
    [XmlElement("B")]
    public B B { get; set; }
}

и в основном вы бы десериализовали его так же, как вы уже делаете.

0 голосов
/ 29 января 2020

Вместо этого вы можете использовать XElement для разбора:

string xml =
    @"<A>
        <B>
            <B1>b1Value</B1>
            <B2>b2Value</B2>
            <B3>b3Value</B3>
        </B>
        <C Attr=""val1""/>
        <C Attr=""val2""/>
        <C Attr=""val3""/>
    </A>";

XElement xe = XElement.Parse(xml);

A a = new A()
{
  Cs = xe.Elements("C").Select(a => new C() { Attr = a.Attribute("Attr").Value }).ToArray(),
  B1 = (string)xe.Element("B").Element("B1"),
  B2 = (string)xe.Element("B").Element("B2"),
  B3 = (string)xe.Element("B").Element("B3")
};
...