需要Parse XML to List <object>,name字段与数据分开

时间:2015-05-07 16:31:42

标签: c# xml web-services xml-parsing

我正在实现一个Windows服务,我需要使用REST的WebService,我想将其解析为List,但我不知道如何。 我的问题是字段的名称与数据分开。

我得到的结构是:

  <?xml version="1.0" encoding="utf-8" ?> 
<xml>
  <result>OK</result> 
<headers>
  <header>lastname</header> 
  <header>firstname</header> 
  <header>Age</header> 
  </headers>
<data>
<datum>
  <item>Kelly</item> 
  <item>Grace</item> 
  <item>33</item> 
</datum>
  </data>
</xml>

2 个答案:

答案 0 :(得分:1)

您可以使用XmlSerializer将该XML反序列化为反映其结构的c#类。例如:

[XmlRoot("xml")]  // Indicates that the root element is named "xml"
public class XmlResponse
{
    [XmlElement("result")] // Indicates that this element is named "result"
    public string Result { get; set; }

    [XmlArray("headers")]  // Indicates two-level list with outer element named "headers" and inner elements named "header"
    [XmlArrayItem("header")]
    public List<string> Headers { get; set; }

    [XmlArray("data")] // Indicates two-level list with outer element named "data" and inner elements named "datum"
    [XmlArrayItem("datum")]
    public List<XmlResponseDatum> Data { get; set; }
}

public class XmlResponseDatum
{
    [XmlElement("item")] // Indicates a one-level list with repeated elements named "item".
    public List<string> Items { get; set; }
}

您可以将其反序列化为:

    public static T LoadFromXML<T>(string xmlString)
    {
        using (StringReader reader = new StringReader(xmlString))
        {
            object result = new XmlSerializer(typeof(T)).Deserialize(reader);
            if (result is T)
            {
                return (T)result;
            }
        }
        return default(T);
    }

    public static string GetXml<T>(T obj)
    {
        using (var textWriter = new StringWriter())
        {
            var settings = new XmlWriterSettings() { Indent = true, IndentChars = "    " }; // For cosmetic purposes.
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj);
            return textWriter.ToString();
        }
    }

    public static void Test()
    {
        string xml = @"<?xml version=""1.0"" encoding=""utf-8"" ?> 
            <xml>
              <result>OK</result> 
            <headers>
              <header>lastname</header> 
              <header>firstname</header> 
              <header>Age</header> 
              </headers>
            <data>
            <datum>
              <item>Kelly</item> 
              <item>Grace</item> 
              <item>33</item> 
            </datum>
              </data>
            </xml>";
        var response = LoadFromXML<XmlResponse>(xml);
        Debug.WriteLine(GetXml(response));

答案 1 :(得分:0)

作为替代方案,这里有一些XDocument并使用不需要Xml装饰的对象。

我提倡这种方法,因为在Xml的结构发生变化的情况下,调整XDocument / Xpath语句更容易.....与XmlAttributes相反。

这也允许使用相同的对象,即使有不同的xml流为其提供保湿。你只需要写一个不同的XDocument&#34;碎纸机&#34;对于每个Xml输入。

[DebuggerDisplay("MyNotUsedStringKey = {MyNotUsedStringKey}")]
public class ImportParent
{
    public ImportParent()
    {
        this.MyNotUsedStringKey = Guid.NewGuid().ToString("N");
        this.ImportChildren = new ImportChildCollection();
    }

    public ImportChildCollection ImportChildren { get; set; }
    public string MyNotUsedStringKey { get; set; }

}

public class ImportChildCollection : List<ImportChild>
{
    public ImportChildCollection() { }
    public ImportChildCollection(IEnumerable<ImportChild> src)
    {
        if (null != src)
        {
            foreach (ImportChild item in src)
            {
                item.Ordinal = this.Count + 1;
                base.Add(item);
            }
        }

        //AddRange(src);
    }
}

[DebuggerDisplay("MyStringKey = {MyStringKey}, MyStringValue='{MyStringValue}', Ordinal='{Ordinal}'")]
public class ImportChild
{
    public ImportChild()
    {
    }

    public int Ordinal { get; set; }
    public string MyStringKey { get; set; }
    public string MyStringValue { get; set; }
}




            string xmlString = @"<?xml version=""1.0"" encoding=""utf-8"" ?> 
            <xml>
                <result>OK</result> 
                <headers>
                    <header>lastname</header>
                    <header>firstname</header>
                    <header>Age</header>
                </headers>
                <data>
                    <datum>
                        <item>Kelly</item>
                        <item>Grace</item>
                        <item>33</item>
                    </datum>
                </data>
            </xml>           ";

            XDocument xDoc = XDocument.Parse(xmlString);

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




            List<ImportParent> parentKeys = new List<ImportParent>
            (
                from list in xDoc.Descendants(ns + "xml")
                from item1 in list.Elements(ns + "headers")
                where item1 != null
                select new ImportParent
                {
                    //note that the cast is simpler to write than the null check in your code
                    //http://msdn.microsoft.com/en-us/library/bb387049.aspx
                    ImportChildren = new ImportChildCollection
                    (
                        from detail in item1.Descendants("header")
                        select new ImportChild
                        {
                            MyStringKey = detail == null ? string.Empty : detail.Value
                        }
                    )
                }
            );


            List<ImportParent> parentValues = new List<ImportParent>
            (
                from list in xDoc.Descendants(ns + "xml")
                from item1 in list.Elements(ns + "data")
                from item2 in item1.Elements(ns + "datum")
                where item1 != null && item2 != null
                select new ImportParent
                {
                    //note that the cast is simpler to write than the null check in your code
                    //http://msdn.microsoft.com/en-us/library/bb387049.aspx
                    ImportChildren = new ImportChildCollection
                        (
                            from detail in item1.Descendants("item")
                            select new ImportChild
                            {
                                MyStringValue = detail == null ? string.Empty : detail.Value
                            }
                        )
                }
            );

            /*Match up the Keys to the Values using "Ordinal" matches*/
            foreach (ImportParent parent in parentKeys)
            {
                foreach (ImportChild child in parent.ImportChildren)
                {
                    ImportChild foundMatch = parentValues.SelectMany(x => x.ImportChildren).Where(c => c.Ordinal == child.Ordinal).FirstOrDefault();
                    if (null != foundMatch)
                    {
                        child.MyStringValue = foundMatch.MyStringValue;
                    }
                }
            }

            foreach (ImportParent parent in parentKeys)
            {
                foreach (ImportChild child in parent.ImportChildren)
                {
                    Console.WriteLine("Key={0}, Value={1}", child.MyStringKey, child.MyStringValue);
                }
            }