4

我遇到了一个问题,我需要基本上反序列化这个:

<?xml version="1.0" encoding="UTF-8"?>
<api_data>
  <status>ok</status>
  <sessions>
    <id>2</id>
    <sessionID>6bfd1f1a7e87a8a6ed476234ad1d6e86</sessionID>
    <gameID>1</gameID>
    <maxPlayers>8</maxPlayers>
    <hostIP>12.0.0.1</hostIP>
    <hostPort>1993</hostPort>
    <inProgress>0</inProgress>
    <timestamp>1358894690</timestamp>
  </sessions>
  <sessions>
    <id>3</id>
    <sessionID>eeb4dc2df32f885c2b7d13f28a246830</sessionID>
    <gameID>1</gameID>
    <maxPlayers>8</maxPlayers>
    <hostIP>12.0.0.1</hostIP>
    <hostPort>1993</hostPort>
    <inProgress>0</inProgress>
    <timestamp>1358894732</timestamp>
  </sessions>
</api_data>

我需要将其转换为可用数据,它也是动态的,所以可能不止 2 个会话元素,可能有 4、20 或 0,我现在的代码刚刚损坏,我想知道什么是让它工作的好方法?

目前我已经到了 XDocument 类的点,所有这些都已加载。我需要用这些数据返回一个多维数组。

编辑:

当前代码,完全损坏:

var xmlSessions = xmlDATA.Descendants("api_data").Elements("sessions").Select(x => x);

result = new string[xmlDATA.Descendants("api_data").Count(), 7];

编辑 2:更多信息

我认为多维数组的方式如下:

array[0,0] "ok" //Status
array[1,0 to 7] //First Session details go here
array[2,0 to 7] //Second session details go here, and so forth.
4

3 回答 3

4

您可以定义以下类表示:

public class api_data
{
    public string status { get; set; }

    [XmlElement]
    public session[] sessions { get; set; }
}

public class session
{
    public int id { get; set; }
    public string sessionID { get; set; }
    public int gameID { get; set; }
    public int maxPlayers { get; set; }
    public string hostIP { get; set; }
    public int hostPort { get; set; }
    public int inProgress { get; set; }
    public int timestamp { get; set; }
}

关键是属性[XmlElement]上的标记sessions,它将指示XmlSerializer使用您提供的模式示例读取/写入 XML。要反序列化它,您可以XmlSerializer这样使用:

//this might change, not sure how you obtain your xml, 
//but let's assume you already have it available as a string
byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(xmlData); 

var stream = new MemoryStream(xmlBytes);
XmlSerializer serializer = new XmlSerializer(typeof(api_data));
api_data apidata = (api_data)serializer.Deserialize(stream);

不需要任何更多的 XML 装饰或设置来读取它(测试和工作)。

编辑:虽然您可能想考虑使用其他一些 XML 属性来转换为一些更好的命名约定,但我们也List<Session>可以引导而不是数组:

[XmlRoot("api_data")]
public class ApiData
{
    [XmlElement("status")]
    public string Status { get; set; }

    [XmlElement("sessions")]
    public List<Session> Sessions { get; set; }
}

public class Session
{
    [XmlElement("id")]
    public int ID { get; set; }

    [XmlElement("sessionID")]
    public string SessionID { get; set; }

    [XmlElement("gameID")]
    public int GameID { get; set; }

    [XmlElement("maxPlayers")]
    public int MaxPlayers { get; set; }

    [XmlElement("hostIP")]
    public string HostIP { get; set; }

    [XmlElement("hostPort")]
    public int HostPort { get; set; }

    [XmlElement("inProgress")]
    public int InProgress { get; set; }

    [XmlElement("timestamp")]
    public int TimeStamp { get; set; }
}

编辑:刚刚注意到你需要把它变成一个多维数组(不知道为什么,但你指定这是遗留的)。好吧,此时,您有一个很好的对象模型,您可以从中进行数据传输。不知道你是怎么打字的,但我们object现在假设类型数组:

ApiData apiData = DeserializeMyApiData(); // from above
array[0][0] = apiData.Status;
for(int i = 1; i <= apiData.Sessions.Count; i++)
{
    var session = apiData.Sessions[i - 1];
    array[i] = new object[8];
    array[i][0] = session.ID;
    array[i][1] = session.SessionID;
    array[i][2] = session.GameID;
    array[i][3] = session.MaxPlayers;
    array[i][4] = session.HostIP;
    array[i][5] = session.HostPort;
    array[i][6] = session.InProgress;
    array[i][7] = session.TimeStamp;
}

无论您有多少会话,这将通过并建立您的阵列。

于 2013-01-26T01:46:28.457 回答
0

如果您真的只想要一个多维数组,您可以使用一行(有点长)代码从该 XML 中获取它:

string[][] items = XDocument.Parse(xml).Root.Elements().Select(e => e.HasElements ? e.Elements().Select(ei => ei.Value).ToArray() : new string[]{ e.Value }).ToArray();

或者使同一条语句更具可读性:

string[][] items = 
    XDocument.Parse(xml).Root
             .Elements().Select(e => e.HasElements ? 
                 e.Elements().Select(ei => ei.Value).ToArray() : new string[]{ e.Value })
             .ToArray();

从那个源 XML 中,这将产生一个像这样的数组:

string[][]
{
   { "ok" },
   { "2", "6bfd1f1a7e87a8a6ed476234ad1d6e86", "1", "8", "12.0.0.1", "1993", "0", "1358894690" },
   { "3", "eeb4dc2df32f885c2b7d13f28a246830", "1", "8", "12.0.0.1", "1993", "0", "1358894732" }
}

如果您想单独获取状态,并将其他值放在多维数组中,您可以这样做:

XDocument doc = XDocument.Parse(xml);
string status = doc.XPathSelectElement("/*/status").Value;
string[][] items = 
    doc.Root.Elements().Where(e => e.HasElements)
       .Select(e => e.Elements().Select(ei => ei.Value).ToArray()).ToArray();

这将产生与上面相同的结果,除了 status 将是一个单独的字符串,并且 items 中不会包含第一个单元素数组:

string[][]
{
   { "2", "6bfd1f1a7e87a8a6ed476234ad1d6e86", "1", "8", "12.0.0.1", "1993", "0", "1358894690" },
   { "3", "eeb4dc2df32f885c2b7d13f28a246830", "1", "8", "12.0.0.1", "1993", "0", "1358894732" }
}
于 2013-01-26T14:12:57.207 回答
0

您可以将“会话”标签包装在“会话列表”标签中吗?

如果是这样,你可以使用这样的东西来加载它:

public class api_data {

    public class sessions {
        public string id { get; set; }
        public string sessionID { get; set; }
        // put all the other vars in here ...
    }

    public string status { get; set; }           
    public List<sessions> session_list { get; set; }

    public static api_data LoadFromXML(string xmlFile) {

        api_data localApiData;

        // serialize from file
        try {
            var xs = new XmlSerializer(typeof(api_data),
                     new XmlRootAttribute("api_data"));
            using (TextReader tr = new StreamReader(xmlFile)) {
                localApiData= xs.Deserialize(tr) as api_data;
            }
        }
        catch (Exception ex) {
            Log.LogError(string.Format(
               "Error reading api_data file {0}: {1}",
               xmlFile, ex.Message));
            return null;
        }


        return localApiData;
    }
}

如果您无法更改 xml 文件的格式,您可能需要在它自己的步骤中加载状态,然后像 api-data 是列表变量一样加载会话,尽管状态存在的事实可能会给您一个错误。

于 2013-01-26T01:31:10.257 回答