对于我的项目,我正在尝试将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;
答案 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('"');
}