在C#中将XML的所有属性获取为2d或3d字符串数组

时间:2014-12-11 15:46:58

标签: c# xml

对于我的项目,我正在尝试将XML API答案翻译或解密为可用的所有信息数组。

以下是我收到的XML示例:

<users>
<User LoginName="test1" Owner="" Alias="" UserType="PAID" ClientType="OBM" Quota="10737418240" Timezone="GMT+08:00 (CST)" Language="en" DataFile="1" DataSize="1536" RetainFile="0" RetainSize="0" EnableMSSQL="Y" EnableMSExchange="Y" EnableOracle="Y" EnableLotusNotes="Y" EnableLotusDomino="Y" EnableMySQL="Y" EnableInFileDelta="Y" EnableShadowCopy="Y" EnableExchangeMailbox="N" ExchangeMailboxQuota="0" EnableNASClient="Y" EnableDeltaMerge="Y" EnableMsVm="N" MsVmQuota="0" EnableVMware="N" VMwareQuota="0" Bandwidth="0" Notes="" Status="ENABLE" RegistrationDate="1302687743242" SuspendPaidUser="N" SuspendPaidUserDate="20140503" LastBackupDate="1302699594652" EnableCDP="Y" EnableShadowProtectBareMetal="Y"EnableWinServer2008BareMetal="Y"
Hostname="123.abc.com" FileSizeLimit="52428800" ExcludeNetworkShare="Y"
><Contact Name=""Email="www@qqq.com"/>
</user>

我已成功使用以下代码获取一个属性:

/// <summary>
        /// Get attribute from XML file USE ONLY AS DEMO
        /// </summary>
        /// <param name="inputXML">XML string</param>
        /// <param name="requestVar">The requested variable in the XML response</param>
        /// <param name="parameter">Where the requested variable is located</param>
        /// <returns>string of all requested variables</returns>
        public static String GetAttribute(string inputXML, string requestVar, string parameter)
        {
            string vars = "";
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(inputXML);

            XmlNodeList xnList = xml.GetElementsByTagName(parameter);
            foreach (XmlNode xn in xnList)
            {
                vars = vars + xn.Attributes[requestVar].Value;
            }
            return vars;
        }

此函数需要可以找到它的节点名称。对于这个项目,需要许多API调用,并且想要一个将所有属性放在字符串数组中的函数。到目前为止,我试图翻译这部分:

vars = vars + xn.Attributes[requestVar].Value;

到此:

foreach (XmlAttribute xa in xn)
{
    vars[i, j, k] = xa.Value;
    k++;
}

和我也尝试过:

for (k = 0; k < xn.Attributes.Count; k++ )
{
    vars[i, j, k] = xn.Attributes[k].Value;
}

但这两个代码都不起作用。如何获得循环或foreach的simpel,它获取数组中的所有属性?这也可以通过以下方式完成:

XmlNodeList xnList = xml.GetElementsByTagName(parameter);

i,j和k变量用于多个循环:i用于XmlNodeList,j用于XmlNode,k用于XmlAttribute。

在这个数组中,我想以相同的顺序获取XML文件的所有信息,只需要“”“之间的部分。

vars[0][0][0]= would stand for: <Users><User LoginName= (vars[<Users>][<User][LoginName]=

这就是我现在的功能:

public static String[,,] GetVars(string inputXML)
        {
            string[,,] vars = new string[100,50,50];
            int i, j, k;
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(inputXML);

            i = j = k = 0;
            XmlNodeList xnList = xml.GetElementsByTagName("Users");
            foreach (XmlNode xn in xnList)
                {
                    foreach (XmlAttribute xa in xn)
                    {
                        vars[i, j, k] = xa.Value;
                        k++;
                    }
                    k = 0;
                    j++;
                }
                j = 0;
            return vars;

2 个答案:

答案 0 :(得分:2)

我会使用System.Xml.Serialization来完成此任务。

首先,我将创建一个包含类的对象,该对象将包含XML将包含的所有元素和属性。

然后将相应的Attributes That Control XML Serialization分配给包含类对象的每个属性。

然后使用XmlSerializer将XML序列化为可用对象。

我在下面提供了一个示例,可以帮助您走上正确的轨道:

包含类对象

namespace XMLSerializationDemo
{
    /// <summary>
    /// A container that contains properties relevant to a RUBI Object
    /// </summary>
    [Serializable]
    public class RUBIObject
    {
        [XmlAttribute]
        public Guid ID { get; set; }

        [XmlAttribute]
        public string Name { get; set; }

        [XmlAttribute]
        public string Description { get; set; }

        [XmlAttribute]
        public DateTime CreatedOn { get; set; }
    }
}

使用某种类型的集合来包装对象。

namespace XMLSerializationDemo
{
    /// <summary>
    /// Object that contains a collection of RUBIObjects which can be serialized into XML
    /// </summary>
    [Serializable]
    public class RUBIObjectCollection
    {
        //Base Constructor which instantiates a collection of RUBIObjects
        public RUBIObjectCollection()
        {
            this.Objects = new List<RUBIObject>();
        }

        public List<RUBIObject> Objects { get; set; }
    } 
}

然后创建用于将xml与对象集合进行序列化的方法:

namespace XMLSerializationDemo
{
    public static class RUBIObjectSerialization
    {
        public static string SerializeToXML(this RUBIObjectCollection source)
        {
            //Create a string writer in order to output to console as opposed to file
            using (var sw = new StringWriter())
            {
                //Settings to configure the way the XML will be output to the console. Really, only Indent = true; is needed.
                var settings = new XmlWriterSettings();
                settings.NewLineChars = Environment.NewLine;
                settings.IndentChars = "  ";
                settings.NewLineHandling = NewLineHandling.Replace;
                settings.Indent = true;

                //Create writer that writes the xml to the string writer object
                using (var xw = XmlWriter.Create(sw, settings))
                {
                    //Create serializer that can serialize a collection of RUBIObjects
                    XmlSerializer serializer =
                        new XmlSerializer(typeof(RUBIObjectCollection));

                    //Serialize this instance of a RUBICollection object, into XML and write to the string writer output
                    serializer.Serialize(xw, source);

                    //Flush the xmlwriter stream as it isn't needed any longer
                    xw.Flush();
                }

                //Return the XML as a formatted string
                return sw.ToString();
            }
        }

        public static RUBIObjectCollection DeserializeToCollection(this string source)
        {
            RUBIObjectCollection collection = null;
            XmlSerializer serializer = null;

            //Read the XML string into a stream.
            using (var sr = new StringReader(source))
            {
                //Instantiate an XML Serializer to expect a collection of RUBI Objects
                serializer = new XmlSerializer(typeof(RUBIObjectCollection));

                //Deserialize the XML stream to a collection
                collection = (RUBIObjectCollection)serializer.Deserialize(sr);
            }

            return collection;
        }
    }
}

这就是从开始到结束所使用的方式:

public class Program
    {
        private static void Main(string[] args)
        {
            //Create test data and add it to a collection
            var collection = DummyData();

            //Serialize the collection to XML and write to console.
            Console.WriteLine(collection.SerializeToXML());

            //Prevents console window from closing
            Console.ReadLine();
        }

        /// <summary>
        /// Generates dummy data for testing purposes
        /// </summary>
        /// <returns>A collection of RUBIObjects</returns>
        private static RUBIObjectCollection DummyData()
        {
            Random random = new Random();
            var collection = new RUBIObjectCollection();

            //Build a collection of RUBIObjects and instantiate them with semi-random data.
            for (int i = 0; i < 10; i++)
            {
                int month = random.Next(1, 12);     //Random month as an integer
                int year = random.Next(2010, 2015); //Random year as an integer

                //Create object and add to collection.
                collection.Objects.Add(new RUBIObject()
                    {
                        ID = Guid.NewGuid(),
                        Name = string.Format("Object{0}", i),
                        Description = "Description",
                        CreatedOn = new DateTime(year, month, 1)
                    });
            }

            return collection;
        }
    }

奖励:你甚至可以在一些单元测试中加入一些光泽!

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using XMLSerializationDemo;

namespace UnitTest
{
    [TestClass]
    public class UnitTest
    {
        [TestMethod]
        public void DummyData_TestDataCreated()
        { 
            //Arrange
            PrivateType pt = new PrivateType(typeof(Program));

            //Act
            RUBIObjectCollection collection = (RUBIObjectCollection)pt.InvokeStatic("DummyData", null);
            int actualResult = collection.Objects.Count;
            int expectedResult = 10;

            //Assert
            Assert.AreEqual(actualResult, expectedResult);
        }

        [TestMethod]
        public void SerializeToXML_GeneratesXMLString()
        {
            //Arrange
            bool actualResult = false;
            bool expectedResult = true;
            PrivateType pt = new PrivateType(typeof(Program));
            RUBIObjectCollection collection = (RUBIObjectCollection)pt.InvokeStatic("DummyData", null);

            //Act
            string serializedXml = collection.SerializeToXML();

            try
            {      
                System.Xml.Linq.XDocument doc = System.Xml.Linq.XDocument.Parse(serializedXml);

                actualResult = true;
            }
            catch
            {
                actualResult = false;
            }

            //Assert
            Assert.AreEqual(actualResult, expectedResult);
        }

        [TestMethod]
        public void DeserializeToCollection_DeserializedToRUBICollection()
        { 
            //Arrange 
            bool actualResult = false;
            bool expectedResult = true;
            XMLSerializationDemo.RUBIObjectCollection deserializedCollection = null;
            PrivateType pt = new PrivateType(typeof(XMLSerializationDemo.Program));
            XMLSerializationDemo.RUBIObjectCollection collection = (XMLSerializationDemo.RUBIObjectCollection)pt.InvokeStatic("DummyData", null);
            string serializedXml = collection.SerializeToXML();

            //Act
            try
            {
                deserializedCollection = serializedXml.DeserializeToCollection();
                if (deserializedCollection.Objects.Count > 0)
                    actualResult = true;
            }
            catch
            {
                actualResult = false;
            }

            //Assert
            Assert.AreEqual(actualResult, expectedResult);
        }
    }
}

SerializeToXML自定义扩展方法生成的示例XML:

<?xml version="1.0" encoding="utf-16"?>
<RUBIObjectCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Objects>
    <RUBIObject ID="dac59571-e7eb-401b-b047-b72bd73628a9" Name="Object0" Description="Description" CreatedOn="2010-07-01T00:00:00" />
    <RUBIObject ID="42d4741b-ba3c-4db6-ac96-24abf819045d" Name="Object1" Description="Description" CreatedOn="2011-04-01T00:00:00" />
    <RUBIObject ID="bc3a2f2f-623a-4e18-be8a-2bf2f3cee841" Name="Object2" Description="Description" CreatedOn="2013-02-01T00:00:00" />
    <RUBIObject ID="51965f3b-c216-42c3-9893-ebe829d0b1d1" Name="Object3" Description="Description" CreatedOn="2014-07-01T00:00:00" />
    <RUBIObject ID="58492a02-291f-497d-87d8-152b7489a0b3" Name="Object4" Description="Description" CreatedOn="2014-06-01T00:00:00" />
    <RUBIObject ID="8b929041-4e6d-42f4-af16-aaa4c3c1d588" Name="Object5" Description="Description" CreatedOn="2011-05-01T00:00:00" />
    <RUBIObject ID="1f17d752-95ad-4d89-a2fe-fec6f5eeb713" Name="Object6" Description="Description" CreatedOn="2010-03-01T00:00:00" />
    <RUBIObject ID="73716b37-7c10-4aa5-9542-8a28d02d1a0b" Name="Object7" Description="Description" CreatedOn="2011-07-01T00:00:00" />
    <RUBIObject ID="a5a8ebe2-487f-462b-938d-49d4d07773bf" Name="Object8" Description="Description" CreatedOn="2014-08-01T00:00:00" />
    <RUBIObject ID="2d84bf1b-c012-495d-a0da-8adf45658ea6" Name="Object9" Description="Description" CreatedOn="2014-03-01T00:00:00" />
    <RUBIObject ID="492d4fe4-ae64-4e91-a38e-9c0353f73ffc" Name="Object10" Description="Description" CreatedOn="2012-06-01T00:00:00" />
  </Objects>
</RUBIObjectCollection>

一旦有了可用对象的集合,就可以用它做你喜欢的事情,例如遍历每个对象并填充你最初请求解决方案的所述2d / 3d数组。

答案 1 :(得分:0)

@JonSkeet,使用Xdocument确实要容易得多。过了一会儿,我成功了并创建了这段代码:

public static String[,] XGetVars(string inputXML)
        {
            XDocument doc = XDocument.Parse(inputXML);
            int i = 0, j = 0, elementscounter = doc.Root.Elements().Count(), attributescounter = doc.Root.Elements().Attributes().Count();
            string[,] vars = new string[elementscounter,(attributescounter/elementscounter)];

            foreach (XElement element in doc.Root.Elements())
            {
                foreach (XAttribute attribute in element.Attributes())
                {
                    vars[i,j] = attribute.ToString();
                    j++;
                }
                j = 0;
                i++;
            }
            return vars;
        }

此方法将创建上述XML的2D字符串数组。我将继续获取节点属性。

编辑: 正如我所承诺的那样,我现在正在使用的新功能:

        /// <summary>
    /// Create 3D array of the XML response
    /// </summary>
    /// <param name="inputXML">string XML file</param>
    /// <returns>3D string array of the XML file</returns>
    public static String[,,] GetVars(string inputXML)
    {
        try
        {
            XDocument doc = XDocument.Parse(inputXML);
            if (doc.Root.Elements().Attributes().Count() < 1 || ErrorMessage(doc)) return new string[1, 1, 1];//temp fix for empty xml files
            int i = 0, j = 0, k = 0, elementscounter = doc.Root.Elements().Count(), attributescounter = doc.Root.Elements().Attributes().Count();
            string[,,] vars = new string[elementscounter, ((attributescounter / elementscounter) + getMaxNodes(doc)), getMaxNodesAttributes(doc)];

            foreach (XElement element in doc.Root.Elements())
            {
                foreach (XAttribute attribute in element.Attributes())
                {
                    vars[i, j, 0] = TrimVar(attribute.ToString());
                    j++;
                }
                foreach (XElement node in element.Nodes())
                {
                    foreach (XAttribute eAttribute in node.Attributes())
                    {
                        vars[i, j, k] = TrimVar(eAttribute.ToString());
                        k++;
                    }
                    k = 0;
                    j++;
                }
                j = 0;
                i++;
            }
            return vars;
        }
        catch (System.Xml.XmlException)
        {
            string[,,] vars = new string[1, 1, 1];
            vars[0, 0, 0] = "No XML found!";
            return vars;
        }
    }
        /// <summary>
        /// get the max nodes available by a Node
        /// </summary>
        /// <param name="XML">XML string</param>
        /// <returns>Max nodes available</returns>
        private static Int32 getMaxNodes(XDocument XML)
        {
            int max = 1;
            foreach (XElement element in XML.Root.Elements())
            {
                if(element.Nodes().Count() > max) max = element.Nodes().Count();
            }
            return max;
        }

        /// <summary>
        /// get the max attributes available by a Node
        /// </summary>
        /// <param name="XML">XML string</param>
        /// <returns>Max attributes available</returns>
        private static Int32 getMaxNodesAttributes(XDocument XML)
        {
            int max = 1;
            foreach (XElement element in XML.Root.Elements())
            {
                foreach (XElement node in element.Nodes())
                {
                    if (node.Attributes().Count() > max) max = node.Attributes().Count();
                }
            }
            return max;
        }

        /// <summary>
        /// Trim the input string to only the value
        /// </summary>
        /// <param name="input">XML readout var</param>
        /// <returns>value of the XML readout var</returns>
        private static String TrimVar(string input)
        {
            return input.Remove(0, (input.IndexOf('"'))+1).TrimEnd('"');
        }