- Home /
Parsing XML - appropriate array size
Hello,
I have a XML-File like this:
<?xml version="1.0" encoding="UTF-8"?>
<dialogs>
<dialog id="2">
<npcText>Hallo, ich bin Melissa</npcText>
<option id = "0">
<optionText>Hallo.</optionText>
<link>3</link>
</option>
<option id = "1">
<optionText>End</optionText>
<link>9999</link>
</option>
</dialog>
<dialog id="3">
<npcText>Schön dich in dieser Stadt zu sehen.</npcText>
<option id = "0">
<optionText>Ich schaue mich mal um</optionText>
<link>9999</link>
</option>
</dialog>
</dialogs>
My arrays:
DialogNode[] dialogs; // store all dialogs
int[] dialogOptions; // this should store the amount of options for each dialog
I can parse them, my DialogManager works with them. This is all fine. And IF I'm preset the size of the arrays (dialog and options array), it work's fine too.
My Problem: I want find the appropiate size of both arrays, which I'm need.
My approach:
Read the XML-File and count all dialogs (assumed in my is a amount of options). Read the XML-File again and read amount of options and store them in my second array (size of array is set by amount of dialogs)
dialogs = new DialogNode[dialogCount];
for(int i = 0; i < dialogCount; i++){
dialogs[i] = new DialogNode();
dialogs[i].options = new Option[optionsCount[i]];
for(int x = 0; x < optionsCount[i];x++){
dialogs[i].options[x] = new Option();
}
}
After this, read the xml-file again and store all data in the right variable of the array. Sorry, is my idea bad?
I don't want to parse the XML more than one time. I want to store all stuff, what I need in this XML.
And in don't want to preset my amount of dialogs and my amount of options for each dialog in the inspector.
Greetings,
V4mpy
Answer by whydoidoit · Oct 17, 2013 at 05:21 PM
You could just use the XML serializer which handles this stuff for you, here is a helper class:
using UnityEngine;
using System.Collections;
using System.Xml.Serialization;
using System.IO;
using System.Text;
using System;
public static class XmlSupport
{
public static T DeserializeXml<T> (this string xml) where T : class
{
if( xml != null ) {
var s = new XmlSerializer (typeof(T));
using (var m = new MemoryStream (Encoding.UTF8.GetBytes (xml)))
{
return (T)s.Deserialize (m);
}
}
return null;
}
public static object DeserializeXml(this string xml, Type tp)
{
var s = new XmlSerializer (tp);
using (var m = new MemoryStream (Encoding.UTF8.GetBytes (xml)))
{
return s.Deserialize (m);
}
}
public static string SerializeXml (this object item)
{
var s = new XmlSerializer (item.GetType ());
using (var m = new MemoryStream())
{
s.Serialize (m, item);
m.Flush ();
return Encoding.UTF8.GetString (m.GetBuffer ());
}
}
}
Then you mark up your classes, here's an example of mine:
using System;
using System.Xml.Serialization;
[Serializable]
[XmlRoot("response")]
public class HighScoreResult
{
public static HighScoreResult Create(string xml)
{
return xml.DeserializeXml<HighScoreResult>();
}
public class HighScoreEntry
{
[XmlElement]
public int position;
[XmlElement]
public int score;
[XmlElement("screenname")]
public string playerName = "";
}
public class HighScoreTableResult
{
[XmlElement]
public string name;
[XmlElement]
public int position;
[XmlElement]
public int score;
[XmlArray("highscoreentries")]
[XmlArrayItem("highscoreentry")]
public HighScoreEntry[] highscoreentries = new HighScoreEntry[0];
}
public class HighScore
{
[XmlArray("highscoretables")]
[XmlArrayItem("highscoretable")]
public HighScoreTableResult[] highscoretables = new HighScoreTableResult[0];
}
[XmlElement]
public HighScore highscore;
}
Then you deserialize one like this:
var result = someXmlString.DeserializeXml<HighScoreResult>();
And serialize it using:
var xml = someXmlSerializableObject.SerializeXml();
Sorry, i don't get this. I'm not familiar with X$$anonymous$$L and Serialization. Is there a easier way to do this? I don't know how to handle with my options (Option) for each Dialog. It sound, weird, but I'm confused.
Ok so here you go (I had to remove the UTF-8 encoding in the start because Unity doesn't like it much):
using System;
using UnityEngine;
using System.Collections;
using System.Xml;
using System.Xml.Serialization;
public class XmlParseDialogs : $$anonymous$$onoBehaviour
{
public string xml=@"<?xml version=""1.0""?>
<dialogs>
<dialog id=""2"">
<npcText>Hallo, ich bin $$anonymous$$elissa</npcText>
<option id = ""0"">
<optionText>Hallo.</optionText>
<link>3</link>
</option>
<option id = ""1"">
<optionText>End</optionText>
<link>9999</link>
</option>
</dialog>
<dialog id=""3"">
<npcText>Schön dich in dieser Stadt zu sehen.</npcText>
<option id = ""0"">
<optionText>Ich schaue mich mal um</optionText>
<link>9999</link>
</option>
</dialog>
</dialogs>";
[Serializable]
[XmlRoot ("dialogs")]
public class Dialogs
{
[XmlElement("dialog")]
public Dialog[] dialogs;
}
[Serializable]
public class Dialog
{
[XmlAttribute]
public int id;
[XmlElement]
public string npcText;
[XmlElement("option")]
public Option[] options;
}
public class Option
{
[XmlAttribute]
public int id;
[XmlElement]
public string optionText;
[XmlElement]
public int link;
}
// Use this for initialization
void Start ()
{
var dialogs = xml.DeserializeXml<Dialogs>();
foreach(var d in dialogs.dialogs)
{
Debug.Log(d.npcText);
foreach(var o in d.options)
{
Debug.Log(o.optionText);
}
}
}
}
It's only double quoted because I embedded it as a verbatim string.
Can you please explain this for my understanding? I want understand this, please. And yes, it works pretty nice. Big thanks.
Answer by V4mpy · Oct 17, 2013 at 04:05 PM
I have a dirty solution. I don't like this solution, but it is possible in this way. My XML:
<dialogs countDialogs = "7">
<temp></temp>
<dialogOptionsCount>2</dialogOptionsCount>
<dialogOptionsCount>2</dialogOptionsCount>
<dialogOptionsCount>2</dialogOptionsCount>
<dialogOptionsCount>1</dialogOptionsCount>
<dialogOptionsCount>3</dialogOptionsCount>
<dialogOptionsCount>1</dialogOptionsCount>
<dialogOptionsCount>1</dialogOptionsCount>
My ManagerScript:
int counter = 0;
XmlReader meinReaderFirst = XmlReader.Create (Application.dataPath + "/XML/dialogs.xml");
while (meinReaderFirst.Read()) {
if (meinReaderFirst.IsStartElement ("dialogs")) {
dialogCount = int.Parse(meinReaderFirst.GetAttribute("countDialogs"));
}
if(meinReaderFirst.IsStartElement("temp")){
optionsCount = new int[dialogCount];
}
if(meinReaderFirst.IsStartElement("dialogOptionsCount")){
optionsCount[counter] = int.Parse(meinReaderFirst.ReadString());
counter++;
}
}
for(int i = 0; i < counter; i++){
Debug.Log("" + optionsCount[i]);
}
Unity debugs:
2
2
2
1
3
1
1
Are there any other solutions?
Answer by darkhog · Oct 17, 2013 at 04:18 PM
IMO you should use dynamic arrays for that. In pseudo code:
while (thereisstillsomethingtoreadoutofxml) {
dialogs.changesize(dialogs.length+1);
dialogs[dialogs.length-1].something1 = xmlobject.getnode("something1") // putting something1 into dialogs.something1
}
This way you also decreasing amount of loops to just one as you are reading and increasing array size as needed. Dialogs of course should be arrays of structs that closely mirrors structure of your xml file.
Can you please give an example? (not pseudo code)
$$anonymous$$y array:
public DialogNode[] dialogs;
and my custom datatype*s*:
[System.Serializable]
public class DialogNode
{
public int id;
public string text;
public Option[] options;
public DialogNode ()
{
this.id = 0;
this.text = "";
}
}`
[System.Serializable]
public class Option
{
public string text;
public int link;
public Option ()
{
this.text = "";
this.link = 0;
}
}
I want a dynamic dialogs (like your way). And additional a dynamic array of options for each dialog.
If you now use List ins$$anonymous$$d of Dialog[] as your type (Namespace System.Collections.Generic) you don't even have to have an explicit line for resizing the array. just use
dialogs.Add(new Option(parseFromXml))
and the list will grow dynamically as needed. The rest of the array syntax will be the same for lists.
Have you considered just marking up the class for X$$anonymous$$L Serialization - it then does it all for you...
Your answer
Follow this Question
Related Questions
Arrays or database? 3 Answers
what is good way to refer array in inspector. 1 Answer
GUI Resize Problem 1 Answer
XML parsing problem - array 0 Answers
how to set an array length? 1 Answer