如何将XML数据解析为自定义C#类的属性?

时间:2022-09-02 13:25:02

Setup

I have this in my Main() function.

我在我的Main()函数中有这个。

List<Token> tokens = new List<Token>();
string path = @"\(some directories)\tokens.xml";
XDocument doc = XDocument.Load(path);

I have this class with a few properties.

我有这个类有一些属性。

public partial class Token
{
    public Token()
    {
        SetURLs = new List<string>();
        SetNames = new List<string>();
    }

    public string Name { get; set; }
    public List<string> SetURLs { get; set; }
    public List<string> SetNames { get; set; }
    public string Color { get; set; }
    public string PT { get; set; }
    public string Text { get; set; }
}

I have this XML file. Here is a snippet.

我有这个XML文件。这是一个片段。

<?xml version="1.0" encoding="UTF-8"?> //EDIT3
<card_database version="2">            //EDIT3
    <cards>
        .
        .
        .
        <card>
            <name>Griffin</name>
            <set picURL="http://magiccards.info/extras/token/duel-decks-ajani-vs-nicol-bolas/griffin.jpg" picURLHq="" picURLSt="">DDH</set>
            <color>w</color>
            <manacost></manacost>
            <type>Token</type>
            <pt>2/2</pt>
            <tablerow>0</tablerow>
            <text>Flying</text>
            <token>1</token>
        </card>
        <card>
            <name>Rat</name>
            <set picURL="http://magiccards.info/extras/token/shadowmoor/rat.jpg" picURLHq="" picURLSt="">SHM</set>
            <set picURL="http://magiccards.info/extras/token/gatecrash/rat.jpg" picURLHq="" picURLSt="">GTC</set>
            <color>b</color>
            <manacost></manacost>
            <type>Token</type>
            <pt>1/1</pt>
            <tablerow>0</tablerow>
            <text></text>
            <token>1</token>
        </card>
        .
        .
        .
    </cards>
</card_database> //EDIT3

As you can see, there are many <card> elements in the <cards> root element. Further, each <card> can have many <set> elements. I made the class accordingly.

如您所见, 根元素中有许多 元素。此外,每个 可以有许多 元素。我相应地上课了。

Problem

How do I go through one <card> at a time and assign the appropriate values to each property?

如何一次浏览一张 并为每个属性分配适当的值?

What I Have Tried

I made a list that contains all of the <name> elements of each <card>. I would then go through this list and assign a name to a new instance of the Token class's Name property. Then populate my tokens list with each new instance.

我创建了一个包含每个 的所有 元素的列表。然后,我将浏览此列表并为Token类的Name属性的新实例指定一个名称。然后使用每个新实例填充我的令牌列表。

List<string> names = new List<string>();
names = doc.Descendants("card").Elements("name").Select(r => r.Value).ToList();
int amount = doc.Descendants("card").Count();

for(int i = 0; i < amount; i++)
{
    Token token = new Token();

    token.Name = name[i];

    .
    .
    .

    tokens.Add(token);
}

I guess I could then make more lists that contain every other desired element and do the same process, but there has to be a more elegant way, right?

我想我可以制作更多包含所有其他所需元素的列表并执行相同的过程,但必须有更优雅的方式,对吧?

EDIT

编辑

I also tried serialization from another question. But for some reason, when I tried to write something from token to the console (say token.Name), it didn't write anything.

我也试过从另一个问题序列化。但出于某种原因,当我尝试将令牌中的东西写入控制台(比如token.Name)时,它没有写任何东西。

XmlSerializer serializer = new XmlSerializer(typeof(Token));
using (StringReader reader = new StringReader(path))
{
    Token token = (Token)(serializer.Deserialize(reader));
}

Probably just an incorrect implementation. If that is the case, could someone use what I posted and show me the correct implementation? Also, I assume this will give 1 or many values to my two List properties, right?

可能只是一个不正确的实现。如果是这种情况,有人可以使用我发布的内容并向我展示正确的实现吗?另外,我假设这会为我的两个List属性提供1个或多个值,对吧?

EDIT

编辑

Thanks for the help.

谢谢您的帮助。

EDIT2

EDIT2

An Answer

After some unsuccessful fiddling with serialization and some more searching, I made an implementation that works.

经过一些不成功的序列化和一些搜索后,我做了一个有效的实现。

foreach (var card in doc.Descendants("card"))
{
    Token token = new Token();

    token.Name = card.Element("name").Value.ToString();
    foreach (var set in card.Elements("set"))
    {
        token.SetURLs.Add(set.Attribute("picURL").Value.ToString());
        token.SetNames.Add(set.Value.ToString());
    }
    token.Color = card.Element("color").Value.ToString();
    token.PT = card.Element("pt").Value.ToString();
    token.Text = card.Element("text").Value.ToString();

    tokens.Add(token);
}

Much better than the number of Lists I first had in mind. Not as succinct as the serialization might have been. However, it does what I need.

比我最初想到的列表数量要好得多。不像序列化那样简洁。但是,它做到了我需要的。

Thanks for the help.

谢谢您的帮助。

EDIT4

EDIT4

Not sure if this many edits are allowed or against etiquette. Just wanted to make this edit for future readers.

不确定这些编辑是否允许或违反礼仪。只是想为未来的读者做这个编辑。

The stuff under the "An Answer" section does solve my problem but the XML Serialization posted below by Dave is much better; it is more flexible and easier to reuse/modify. So, pick the solution that has more benefits for your situation.

“答案”部分下的内容确实解决了我的问题,但Dave下面发布的XML序列化要好得多;它更灵活,更容易重用/修改。因此,选择对您的情况有更多好处的解决方案。

3 个解决方案

#1


9  

Using XML Serialization I was able to deserialize your snippet into some objects. I don't really understand your 2 different list variables so i modified it into 1 list.

使用XML序列化我能够将您的代码段反序列化为某些对象。我真的不明白你的2个不同的列表变量,所以我把它修改为1个列表。

I am not sure if this is exactly what you are trying to pull off, but i believe it should help you with your xml deserialization of multiple "set" elements.

我不确定这是否正是你想要完成的,但我相信它应该可以帮助你对多个“set”元素进行xml反序列化。

I created a file with your same snippet named tokens.xml, edited to match your new layout.

我创建了一个名为tokens.xml的相同代码段的文件,编辑后与您的新布局相匹配。

<?xml version="1.0" encoding="UTF-8"?> 
<card_database version="2">
  <cards>
    <card>
      <name>Griffin</name>
      <set picURL="http://magiccards.info/extras/token/duel-decks-ajani-vs-nicol-bolas/griffin.jpg" picURLHq="" picURLSt="">DDH</set>
      <color>w</color>
      <manacost></manacost>
      <type>Token</type>
      <pt>2/2</pt>
      <tablerow>0</tablerow>
      <text>Flying</text>
      <token>1</token>
    </card>
    <card>
      <name>Rat</name>
      <set picURL="http://magiccards.info/extras/token/shadowmoor/rat.jpg" picURLHq="" picURLSt="">SHM</set>
      <set picURL="http://magiccards.info/extras/token/gatecrash/rat.jpg" picURLHq="" picURLSt="">GTC</set>
      <color>b</color>
      <manacost></manacost>
      <type>Token</type>
      <pt>1/1</pt>
      <tablerow>0</tablerow>
      <text></text>
      <token>1</token>
    </card>
  </cards>
</card_database>

I created a few classes

我创建了几个类

[XmlRoot(ElementName = "card_database")]
public class CardsDatabase
{
    public CardsDatabase()
    {

    }
    [XmlElement(ElementName = "cards", Form = XmlSchemaForm.Unqualified)]
    public CardsList Cards { get; set; }

    [XmlAttribute(AttributeName = "version", Form = XmlSchemaForm.Unqualified)]
    public string Version { get; set; }
}

[XmlRoot(ElementName = "cards")]
public class CardsList
{
    public CardsList()
    {
        Cards = new List<Card>();
    }
    [XmlElement(ElementName = "card", Form = XmlSchemaForm.Unqualified)]
    public List<Card> Cards { get; set; } 
}

[XmlRoot(ElementName = "card")]
public class Card
{
    public Card()
    {
        SetURLs = new List<SetItem>();

    }

    [XmlElement(ElementName = "name", Form = XmlSchemaForm.Unqualified)]
    public string Name { get; set; }

    [XmlElement(ElementName = "set", Form = XmlSchemaForm.Unqualified)]
    public List<SetItem> SetURLs { get; set; }

    [XmlElement(ElementName = "color", Form = XmlSchemaForm.Unqualified)]
    public string Color { get; set; }

    [XmlElement(ElementName = "pt", Form = XmlSchemaForm.Unqualified)]
    public string PT { get; set; }

    [XmlElement(ElementName = "text", Form = XmlSchemaForm.Unqualified)]
    public string Text { get; set; }

}

[XmlRoot(ElementName = "set")]
public class SetItem
{
    public SetItem()
    {

    }

    [XmlAttribute(AttributeName = "picURL", Form = XmlSchemaForm.Unqualified)]
    public string PicURL { get; set; }

    [XmlAttribute(AttributeName = "picURLHq", Form = XmlSchemaForm.Unqualified)]
    public string PicURLHq { get; set; }

    [XmlAttribute(AttributeName = "picURLSt", Form = XmlSchemaForm.Unqualified)]
    public string PicURLSt { get; set; }

    [XmlText]
    public string Value { get; set; }
}

The main body is as follows (I know this is ugly, but i was going fast so please improve)

主体如下(我知道这是丑陋的,但我快速,所以请改进)

CardsDatabase cards = new CardsDatabase();
string path = @"tokens.xml";
XmlDocument doc = new XmlDocument();
doc.Load(path);

XmlSerializer serializer = new XmlSerializer(typeof(CardsDatabase));
using (StringReader reader = new StringReader(doc.InnerXml))
{
    cards = (CardsDatabase)(serializer.Deserialize(reader));
}

The following is what the output looked like.

以下是输出的样子。

如何将XML数据解析为自定义C#类的属性?

#2


1  

With Linq to Xml,

使用Linq到Xml,

string path = @"~/tokens.xml";
var doc = XDocument.Load(Server.MapPath(Url.Content(path)));


var cards = doc.Descendants("card")
    .Select(x =>
        new Token
        {
            Name = x.Element("name").Value,
            SetURLs = x.Elements("set").Select(y => y.Attribute("picURL").Value)
                                       .ToList(),
            SetNames = x.Elements("set").Select(y => y.Value).ToList(),
            Color = x.Element("color").Value,
            PT = x.Element("pt").Value,
            Text = x.Element("text").Value
        }).ToList();

hope this helps.

希望这可以帮助。

#3


0  

Check out this post:

看看这篇文章:

XPath and *.csproj

XPath和* .csproj

But take the below and convert the anonymous types to your concrete class(es). It should be enough to get you started.

但是请使用下面的内容并将匿名类型转换为具体类。它应该足以让你开始。

            XDocument xDoc = /* populate from somewhere */

            XNamespace nsPlaceHolder = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");

  XNamespace ns = string.Empty;


            var list1 = from list in xDoc.Descendants(ns + "cards")
                        from item in list.Elements(ns + "card")
                        /* where item.Element(ns + "card") != null */
                    select new
                       {

                           PicURL = item.Attribute("picURL").Value,
                           MyName = (item.Element(ns + "name") == null) ? string.Empty : item.Element(ns + "name").Value
                       };


            foreach (var v in list1)
            {
                Console.WriteLine(v.ToString());
            }

#1


9  

Using XML Serialization I was able to deserialize your snippet into some objects. I don't really understand your 2 different list variables so i modified it into 1 list.

使用XML序列化我能够将您的代码段反序列化为某些对象。我真的不明白你的2个不同的列表变量,所以我把它修改为1个列表。

I am not sure if this is exactly what you are trying to pull off, but i believe it should help you with your xml deserialization of multiple "set" elements.

我不确定这是否正是你想要完成的,但我相信它应该可以帮助你对多个“set”元素进行xml反序列化。

I created a file with your same snippet named tokens.xml, edited to match your new layout.

我创建了一个名为tokens.xml的相同代码段的文件,编辑后与您的新布局相匹配。

<?xml version="1.0" encoding="UTF-8"?> 
<card_database version="2">
  <cards>
    <card>
      <name>Griffin</name>
      <set picURL="http://magiccards.info/extras/token/duel-decks-ajani-vs-nicol-bolas/griffin.jpg" picURLHq="" picURLSt="">DDH</set>
      <color>w</color>
      <manacost></manacost>
      <type>Token</type>
      <pt>2/2</pt>
      <tablerow>0</tablerow>
      <text>Flying</text>
      <token>1</token>
    </card>
    <card>
      <name>Rat</name>
      <set picURL="http://magiccards.info/extras/token/shadowmoor/rat.jpg" picURLHq="" picURLSt="">SHM</set>
      <set picURL="http://magiccards.info/extras/token/gatecrash/rat.jpg" picURLHq="" picURLSt="">GTC</set>
      <color>b</color>
      <manacost></manacost>
      <type>Token</type>
      <pt>1/1</pt>
      <tablerow>0</tablerow>
      <text></text>
      <token>1</token>
    </card>
  </cards>
</card_database>

I created a few classes

我创建了几个类

[XmlRoot(ElementName = "card_database")]
public class CardsDatabase
{
    public CardsDatabase()
    {

    }
    [XmlElement(ElementName = "cards", Form = XmlSchemaForm.Unqualified)]
    public CardsList Cards { get; set; }

    [XmlAttribute(AttributeName = "version", Form = XmlSchemaForm.Unqualified)]
    public string Version { get; set; }
}

[XmlRoot(ElementName = "cards")]
public class CardsList
{
    public CardsList()
    {
        Cards = new List<Card>();
    }
    [XmlElement(ElementName = "card", Form = XmlSchemaForm.Unqualified)]
    public List<Card> Cards { get; set; } 
}

[XmlRoot(ElementName = "card")]
public class Card
{
    public Card()
    {
        SetURLs = new List<SetItem>();

    }

    [XmlElement(ElementName = "name", Form = XmlSchemaForm.Unqualified)]
    public string Name { get; set; }

    [XmlElement(ElementName = "set", Form = XmlSchemaForm.Unqualified)]
    public List<SetItem> SetURLs { get; set; }

    [XmlElement(ElementName = "color", Form = XmlSchemaForm.Unqualified)]
    public string Color { get; set; }

    [XmlElement(ElementName = "pt", Form = XmlSchemaForm.Unqualified)]
    public string PT { get; set; }

    [XmlElement(ElementName = "text", Form = XmlSchemaForm.Unqualified)]
    public string Text { get; set; }

}

[XmlRoot(ElementName = "set")]
public class SetItem
{
    public SetItem()
    {

    }

    [XmlAttribute(AttributeName = "picURL", Form = XmlSchemaForm.Unqualified)]
    public string PicURL { get; set; }

    [XmlAttribute(AttributeName = "picURLHq", Form = XmlSchemaForm.Unqualified)]
    public string PicURLHq { get; set; }

    [XmlAttribute(AttributeName = "picURLSt", Form = XmlSchemaForm.Unqualified)]
    public string PicURLSt { get; set; }

    [XmlText]
    public string Value { get; set; }
}

The main body is as follows (I know this is ugly, but i was going fast so please improve)

主体如下(我知道这是丑陋的,但我快速,所以请改进)

CardsDatabase cards = new CardsDatabase();
string path = @"tokens.xml";
XmlDocument doc = new XmlDocument();
doc.Load(path);

XmlSerializer serializer = new XmlSerializer(typeof(CardsDatabase));
using (StringReader reader = new StringReader(doc.InnerXml))
{
    cards = (CardsDatabase)(serializer.Deserialize(reader));
}

The following is what the output looked like.

以下是输出的样子。

如何将XML数据解析为自定义C#类的属性?

#2


1  

With Linq to Xml,

使用Linq到Xml,

string path = @"~/tokens.xml";
var doc = XDocument.Load(Server.MapPath(Url.Content(path)));


var cards = doc.Descendants("card")
    .Select(x =>
        new Token
        {
            Name = x.Element("name").Value,
            SetURLs = x.Elements("set").Select(y => y.Attribute("picURL").Value)
                                       .ToList(),
            SetNames = x.Elements("set").Select(y => y.Value).ToList(),
            Color = x.Element("color").Value,
            PT = x.Element("pt").Value,
            Text = x.Element("text").Value
        }).ToList();

hope this helps.

希望这可以帮助。

#3


0  

Check out this post:

看看这篇文章:

XPath and *.csproj

XPath和* .csproj

But take the below and convert the anonymous types to your concrete class(es). It should be enough to get you started.

但是请使用下面的内容并将匿名类型转换为具体类。它应该足以让你开始。

            XDocument xDoc = /* populate from somewhere */

            XNamespace nsPlaceHolder = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");

  XNamespace ns = string.Empty;


            var list1 = from list in xDoc.Descendants(ns + "cards")
                        from item in list.Elements(ns + "card")
                        /* where item.Element(ns + "card") != null */
                    select new
                       {

                           PicURL = item.Attribute("picURL").Value,
                           MyName = (item.Element(ns + "name") == null) ? string.Empty : item.Element(ns + "name").Value
                       };


            foreach (var v in list1)
            {
                Console.WriteLine(v.ToString());
            }