Parsing XML metadata containing conditional statements with C# in Unity - c#

I have an XML file full of events like this one with multiple statements to check.
How is this action even called? I'm so lost that I don't even know where to start looking.
<BENEvents>
<BENDescisionQ1 flagBEN_00="true" flagBEN_01="true" flagBEN_28="true" flagBEN_29="false">
<AskQuestions caption='Looking today again at you glass with milk you decide....'>
<Question event='DescisionQ1Yes'>Cowcostumes look great.</Question>
<Question event='DescisionQ1No'>Flatnesss is justice, so NO</Question>
</AskQuestions>
</BENDescisionQ1>
<BENDescisionQ2 ....>
.....
</BENDescisionQ2>
<BENEvents>
Please help to point me in the right direction.
EDIT: THe answer solved my question, thatnk you
This is how my code ended up for now to deal with more general events.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using System.IO;
public class mllhildTestLinq : MonoBehaviour
{
public mllhildTestController controller;
public void QueryXML(string filename, string parentNode, GameObject listForDisplay)//(string[] args)
{
List<GeneralEvent> listEvents = new List<GeneralEvent>();
GeneralEvent GeneralEvents = new GeneralEvent();
listEvents = GeneralEvents.parse(filename, parentNode);
// just printing for testing
//Debug.Log("Is this shit getting here?");
int i = 0;
foreach (GeneralEvent newEvent in listEvents)
{
//Debug.Log(i);
listForDisplay.GetComponent<PrefabListButtoms>().AddNewButton(newEvent.nodeName, listForDisplay);
Debug.Log(newEvent.nodeName);
i++;
foreach (KeyValuePair<string, string> keyValuePair in newEvent.general)
{
Debug.Log(keyValuePair.Key + " " + keyValuePair.Value);
}
//for (int i = 0; i < newEvent.general.Count; i++)
//{
// controller.AddText(" key: " + newEvent.general[i].Key + " value: " + newEvent.general[i].Value);
//}
//controller.AddText("\n");
}
}
}
public class GeneralEvent
{
public static List<GeneralEvent> listEvents = new List<GeneralEvent>();
public string nodeName { get; set; }
public List<KeyValuePair<string, string>> general { get; set; }
//string patternNumber = #"\d+$";
string patternGeneral = #"[^\d]+[^\$]+";
public List<GeneralEvent> parse(string filename, string parentNode)
{
listEvents.Clear();
XElement generalEvents;
XDocument doc = XDocument.Load(filename);
try
{
generalEvents = doc.Descendants(parentNode).First();
//generalEvents = doc.Elements(parentNode).FirstOrDefault();
}
catch
{
generalEvents = null;
}
//XElement generalEvents = doc.Descendants(parentNode).FirstOrDefault();
if (generalEvents != null)
{
//Debug.Log("---------------------------------------------------------------------");
foreach (XElement descision in generalEvents.Elements())
{
GeneralEvent newEvent = new GeneralEvent();
listEvents.Add(newEvent);
//Debug.Log(descision.Name);
// newEvent.nodeName = string.Parse(Regex.Match(descision.Name.LocalName, patternGeneral).Value);
newEvent.nodeName = descision.Name.ToString();
newEvent.general = descision.Attributes()
.Select(x => new KeyValuePair<string, string>(Regex.Match(x.Name.LocalName, patternGeneral).Value, (string)x)).ToList();
}
}
else
{
Debug.Log("null");
}
return listEvents;
}
}

This is not a simple Xml Parse. See my Xml Linq solution using Regex
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
BenEvent benEvent = new BenEvent();
benEvent.parse(FILENAME);
}
}
public class BenEvent
{
public static List<BenEvent> listEvents = new List<BenEvent>();
public int number { get; set; }
public List<KeyValuePair<int, Boolean>> flags { get; set; }
public string question { get; set; }
public List<KeyValuePair<string, string>> answers { get; set; }
string patternNumber = #"\d+$";
string patternYesNo = #"[^\d]+$";
public void parse(string filename)
{
XDocument doc = XDocument.Load(filename);
XElement benEvents = doc.Descendants("BENEvents").FirstOrDefault();
foreach (XElement descision in benEvents.Elements())
{
BenEvent newEvent = new BenEvent();
listEvents.Add(newEvent);
newEvent.number = int.Parse(Regex.Match(descision.Name.LocalName, patternNumber).Value);
newEvent.flags = descision.Attributes()
.Select(x => new KeyValuePair<int, Boolean>(int.Parse(Regex.Match(x.Name.LocalName, patternNumber).Value), (Boolean)x)).ToList();
newEvent.question = (string)descision.Element("AskQuestions").Attribute("caption");
newEvent.answers = descision.Descendants("Question")
.Select(x => new KeyValuePair<string, string>(Regex.Match((string)x.Attribute("event"), patternYesNo).Value, (string)x)).ToList();
}
}
}
}

Related

How to resolve System.InvalidOperationException. Inaccessible due to its protection level. Only public types can be processed

I am trying to do an exercise about write and read data to file. The program have room, customer and hotel class and after i create object and give value for it, i try to serilize and write it to file in XML format but i encounter the exception above. I have try an example about this and it is running normally. Am i missing some declaration somewhere?
This is my XMLSerializer.cs:
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace Assignment7
{
class XMLSerializer
{
string filePath;
public XMLSerializer(string filePath)
{
this.filePath = filePath;
}
//This generic method serializes (writes) the object of generic data type to the file.
public string WriteXML<T>(T type)
{
StringBuilder feedback = new StringBuilder();
feedback.AppendLine("Provided data is invalid!");
if (type == null)
return feedback.ToString();
//Here we define an XmlSerializer object
XmlSerializer xmlSerializer = new XmlSerializer(type.GetType());
//Here we define an XmlWriter object and define settings for it.
XmlWriter xmlWriter = XmlWriter.Create(filePath,
new XmlWriterSettings()
{
OmitXmlDeclaration = true,
//ConformanceLevel specifies the level of conformance
//(document, fragment, or automatic detection).
//The default is Document.
ConformanceLevel = ConformanceLevel.Auto,
Indent = true
});
//Here we serialize data to the file
xmlSerializer.Serialize(xmlWriter, type);
//Here we clos ehe stream
xmlWriter.Close();
FileInfo fileInfo = new FileInfo(filePath);
if (fileInfo.Exists)
{
feedback.Clear();
feedback.AppendLine(fileInfo.FullName + " exists? " + fileInfo.Exists + ". Current length: " + fileInfo.Length);
}
return feedback.ToString();
}
}
}
This is my Program.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Asignment7
{
class Program
{
static void Main(string[] args)
{
string filePath = #"D:\Study\Windows\hotel.xml";
Room tulip = new Room("A01", "South", "Single", 20, "Small room suitable for 1 person.");
Room lily = new Room("A11", "North", "Double", 40, "Big room for couple.");
Room blossom = new Room("B01", "East", "President", 150, "Luxury experience room.");
ArrayList rooms = new ArrayList { tulip, lily, blossom };
Customer Cus1 = new Customer("Trung", "401 Voyrinkatu", "14/02", 1);
Customer Cus2 = new Customer("Viet", "52 Handel", "14/03", 3);
Customer Cus3 = new Customer("David", "50 Palosarentie", "28/02", 2);
ArrayList customers = new ArrayList { Cus1, Cus2, Cus3 };
Hotel hotel = new Hotel("Lion Head", "18-03-1999", "Korsholm 89, Vaasa", 50, rooms, customers);
XMLSerializer xmlSerializer = new XMLSerializer(filePath);
Console.WriteLine(xmlSerializer.WriteXML<Room>(tulip));
Console.ReadLine();
}
}
}
This is my Hotel.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace Assignment7
{
[XmlRoot("hotel")]
class Hotel
{
[XmlElement("name")]
public string HotelName { get; set; }
[XmlElement("date")]
public string ConstructionDate { get; set; }
[XmlElement("address")]
public string Address { get; set; }
[XmlElement("staff")]
public int Staff { get; set; }
[XmlIgnore]
public ArrayList Rooms { get; set; }
[XmlIgnore]
public ArrayList Customers { get; set; }
public Hotel() { }
public Hotel(string name, string constructionDate, string address, int staff, ArrayList rooms, ArrayList customers)
{
this.HotelName = name;
this.ConstructionDate = constructionDate;
this.Address = address;
this.Staff = staff;
this.Rooms = rooms;
this.Customers = customers;
}
}
}
This is my Room.cs:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace Assignment7
{
[XmlRoot("room")]
class Room
{
[XmlElement("number")]
public string RoomNumber { get; set; }
[XmlElement("area")]
public string Area { get; set; }
[XmlElement("type")]
public string Type { get; set; }
[XmlElement("price")]
public double PricePerNight { get; set; }
[XmlElement("description")]
public string Description { get; set; }
public Room() { }
public Room(string roomNumber, string area, string type, double pricePerNight, string description)
{
this.RoomNumber = roomNumber;
this.Area = area;
this.Type = type;
this.PricePerNight = pricePerNight;
this.Description = description;
}
}
}
This is my Customer.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace Assignment7
{
[XmlRoot("customer")]
class Customer
{
[XmlElement("name")]
public string CustomerName
{
get; set;
}
[XmlElement("room")]
public string RoomNumber
{
get; set;
}
[XmlElement("arrival")]
public string ArrivalDate
{
get; set;
}
[XmlElement("length")]
public int LengthOfStay
{
get; set;
}
public Customer() { }
public Customer(string name, string roomNumber, string arrivalDate, int lengthOfStay)
{
this.CustomerName = name;
this.RoomNumber = roomNumber;
this.ArrivalDate = arrivalDate;
this.LengthOfStay = lengthOfStay;
}
}
}

How I can deserialize a System.Xml.Linq.XElement?

I tried:
using (XmlReader reader = XmlReader.Create(_xmlPath))
{
while (reader.Read())
{
if (reader.NodeType.Equals(XmlNodeType.Element) && reader.Name.Equals("Obj"))
{
Obj obj = new Obj();
while (reader.Read())
{
if (reader.NodeType.Equals(XmlNodeType.EndElement) && reader.Name.Equals("Obj"))
break;
if (reader.NodeType.Equals(XmlNodeType.Element))
{
switch (reader.Name)
{
case "Code":
obj.Code = reader.ReadElementContentAsString();
break;
case "Data":
XElement el = (XElement) XNode.ReadFrom(reader);
XmlReader r = el.CreateReader();
XmlSerializer serializer = new XmlSerializer(typeof(Data));
Data data = (Data) serializer.Deserialize(r);
obj.Data = data;
break;
}
}
}
}
}
}
Xml :
<Root>
<Obj>
<Code>code</Code>
<Data>
<Date>2020-08-07</Date>
<Amount>1000</Amount>
</Data>
</Obj>
</Root>
Data class :
public class Data{
public DateTime Date {get;set;}
public decimal Amount {get;set;}
}
Normally, it's a large XML file, this is why I try to cut it to fragments and I use XmlReader to parse it.
The deserialization doesn't work, if you have other ways I'm a taker
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Data data = doc.Descendants("Data")
.Select(x => new Data() { Date = (DateTime)x.Element("Date"), Amount = (decimal)x.Element("Amount") }).FirstOrDefault();
}
}
public class Data
{
public DateTime Date { get; set; }
public decimal Amount { get; set; }
}
}
For huge files use following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
List<Data> data = new List<Data>();
while (!reader.EOF)
{
if (reader.Name != "Data")
{
reader.ReadToFollowing("Data");
}
if (!reader.EOF)
{
XElement xData = (XElement)XElement.ReadFrom(reader);
Data newData = new Data() { Date = (DateTime)xData.Element("Date"), Amount = (decimal)xData.Element("Amount") };
data.Add(newData);
}
}
}
}
public class Data
{
public DateTime Date { get; set; }
public decimal Amount { get; set; }
}
}
I simplified your code. It should work.
var serializer = new XmlSerializer(typeof(Obj));
using (XmlReader reader = XmlReader.Create(_xmlPath))
{
while (reader.ReadToFollowing("Obj"))
{
Obj obj = (Obj)serializer.Deserialize(reader);
}
}
If the actual xml has a more complex structure and this code doesn't work, let us know.

How to serialize XML array/list as sequentially named elements

I need help serializing XML in C#/.net.
Given something like this in C#:
public class Action {
public string Name;
public string Type;
}
public class TestObject {
public List<Action> Actions;
}
I want to serialize the list of actions as elements, each with a unique name:
<TestObject>
<Action0>
<Name>A</Name>
<Type>Dog</Name>
</Action0>
<Action1>...</Action1>
<Action2>...</Action2>
...
</TestObject>
I've been looking into using IXmlSerializable on a custom List object to replace TestObject. But I'm not sure how to proceed.
Is this on the right track?
public class ActionCollection<T> : List<T>, IXmlSerializable ...
public class TestObject : ActionCollection<Action> { ...
The other possibility that comes to mind is - some way to customize the serialization of each Action to override the element name using C# code that could add the digit?
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
TestObject tests = new TestObject() {
Actions = new List<Action>() {
new Action() { Name = "A", Type = "Dog"},
new Action() { Name = "C", Type = "Cat"},
new Action() { Name = "E", Type = "Elephant"}
}
};
string root = "<TestObject></TestObject>";
XDocument doc = XDocument.Parse(root);
XElement testObject = doc.Root;
int index = 0;
foreach (Action action in tests.Actions)
{
XElement newAction = new XElement("Action" + index.ToString(), new object[] {
new XElement("Name", action.Name),
new XElement("Type", action.Type)
});
testObject.Add(newAction);
index++;
}
doc.Save(FILENAME);
}
}
public class Action
{
public string Name;
public string Type;
}
public class TestObject
{
public List<Action> Actions;
}
}
Using a Custom Xml Serializer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.Schema;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
TestObject tests = new TestObject() {
Actions = new List<Action>() {
new Action() { Name = "A", Type = "Dog"},
new Action() { Name = "C", Type = "Cat"},
new Action() { Name = "E", Type = "Elephant"}
}
};
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(FILENAME,settings);
XmlSerializer serializer = new XmlSerializer(typeof(TestObject));
serializer.Serialize(writer, tests);
}
}
public class Action
{
public string Name;
public string Type;
}
public class TestObject : IXmlSerializable
{
public List<Action> Actions;
public void WriteXml(XmlWriter writer)
{
List<XElement> testObjects = new List<XElement>();
int index = 0;
foreach (Action action in Actions)
{
XElement newAction = new XElement("Action" + index.ToString(), new object[] {
new XElement("Name", action.Name),
new XElement("Type", action.Type)
});
testObjects.Add(newAction);
index++;
}
string obj = string.Join("", testObjects.Select(x => x.ToString()));
writer.WriteRaw("\n" + obj + "\n");
}
public void ReadXml(XmlReader reader)
{
}
public XmlSchema GetSchema()
{
return (null);
}
}
}

ASP.Net ElasticSearch

Hello so I am trying to code a simple web view, with asp.net and NEST library, that will take my ElasticSearch database, and show it in textview on button click.
This is the code that I input when my button is clicked,
would you please look at it and tell me am I on a good path or something is not good.
using Elasticsearch.Net;
using Nest;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ElasticsearchWeb
{
public class shekspir
{
public string type { get; set; }
public int line_id { get; set; }
public string play_name { get; set; }
public int speech_number { get; set; }
public float line_number { get; set; }
public string speaker { get; set; }
public string text_entry { get; set; }
}
public partial class Default : System.Web.UI.Page
{
public static Uri GetElasticHost()
{
var host = "http://localhost:9200";
return new Uri(host);
}
public static ElasticClient GetElasticClient(ConnectionSettings settings = null)
{
if (settings == null)
{
var node = GetElasticHost();
var pool = new SingleNodeConnectionPool(node);
settings = new ConnectionSettings(pool);
}
settings.DisableDirectStreaming(true);
var client = new ElasticClient(settings);
return client;
}
public static List<shekspir> GetAllShekspir(int ID)
{
var workОfShakespeare = GetElasticClient();
ISearchResponse<shekspir> result = null;
result = workОfShakespeare.Search<shekspir>(x => x
.Index("shekspir")
.Query(q => q
.MatchAll())
.Size(100)
);
List<shekspir> list = new List<shekspir>();
foreach (var r in result.Hits)
{
shekspir a = r.Source;
list.Add(a);
}
return list;
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
List<shekspir> list = GetAllShekspir (1);
foreach (shekspir u in list)
{
litInfo.Text += u.play_name + ": " + u.text_entry + "<br>";
}
}
}
}
List<shekspir> list = new List<shekspir>();
foreach (var r in result.Hits)
{
shekspir a = r.Source;
list.Add(a);
}
If you just want the returned documents above can be replaced by
var list= result.Documents

how to read items from file into a list of items and set the properties to the value in the file?

Hello I am trying to create a stock log system in c# winforms and i am a bit stuck for ideas on how to read the items back into a list and storing the data into the properties.
I will be reading in from a csv file where each line is 1 item and each property is separated by a comma.
the main Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//using System.IO;
//using Microsoft.VisualBasic;
namespace stock_list
{
public partial class Form1 : Form
{
private List<item> itemlist = new List<item>((1));
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnSave_Click(object sender, EventArgs e)
{
saveitem(Convert.ToInt64(txtStallNumber.Text), Convert.ToInt64(txtStockNumber.Text), txtDescription.Text, Convert.ToDecimal(txtPaidprice.Text), Convert.ToDecimal(txtSoldPrice.Text));
}
private void btnItems_Click(object sender, EventArgs e)
{
readfromfile();
}
private void readfromfile()
{
var reader = new System.IO.StreamReader(#"file.csv", Encoding.UTF8, false);
while (!reader.EndOfStream)
{
//what todo here??
}
}
private void saveitem(long stallnumberpar, long stocknumberpar, string itemdiscriptionpar, decimal boughtpricepar, decimal soldpricepar, decimal profitorlosspar = 0)
{
itemlist.Add(new item { stallnumber = stallnumberpar, stocknumber = stocknumberpar, itemdescription = itemdiscriptionpar, boughtprice = boughtpricepar, soldprice = soldpricepar, profitorloss = soldpricepar - boughtpricepar});
txtDescription.Clear();
txtPaidprice.Clear();
txtSoldPrice.Clear();
txtStallNumber.Text = "";
txtStockNumber.Clear();
txtStallNumber.Focus();
MessageBox.Show("Item Saved");
}
private void btnQuery_Click(object sender, EventArgs e)
{
RunQueryDescription(Microsoft.VisualBasic.Interaction.InputBox("Enter Search Criteria", "Enter Search Criteria", "Default",0,0));
}
private void RunQueryDescription(string description)
{
//List<item> products = new List<item>((1));
var writer = new System.IO.StreamWriter(#"file.csv", true, Encoding.UTF8);
item[] productsarr = new item[itemlist.Count];
int index = 0;
foreach (item product in itemlist)
{
if (product.itemdescription.Contains(description))
{
productsarr[index] = product;
index++;
}
else
{
index++;
continue;
}
}
for (int i = 0; i < productsarr.Length; i++)
{
MessageBox.Show(productsarr[i].stallnumber.ToString() +
productsarr[i].stocknumber.ToString() +
productsarr[i].itemdescription.ToString() +
productsarr[i].boughtprice.ToString() +
productsarr[i].soldprice.ToString() +
productsarr[i].profitorloss.ToString());
writer.Write(productsarr[i].stallnumber.ToString() + "," +
productsarr[i].stocknumber.ToString() + "," +
productsarr[i].itemdescription.ToString() + "," +
productsarr[i].boughtprice.ToString() + "," +
productsarr[i].soldprice.ToString() + "," +
productsarr[i].profitorloss.ToString());
writer.Close();
writer.Dispose();
}
}
}
}
The items class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
namespace stock_list
{
class item
{
public long stallnumber { get; set; }
public long stocknumber { get; set; }
public string itemdescription { get; set; }
public decimal boughtprice { get; set; }
public decimal soldprice { get; set; }
public decimal profitorloss { get; set; }
}
}
EDIT:
Example File
1,1,Vase,1.00,2.00,1.00
Any help will be valued
Thanks in Advance!
You can use the File.ReadAllLines to read the file
private List<item> itemlist = new List<item>();
private void readfromfile()
{
var lines = System.IO.File.ReadAllLines("path");
foreach (string item in lines)
{
var values = item.Split(',');
itemlist.Add(new item()
{
stallnumber = long.Parse(values[0]),
stocknumber = long.Parse(values[1]),
itemdescription = values[2],
//and so on
});
}
}
Try splitting each line on the delimiter (most likely a comma), and then parse out the line and add a new instance of item to your list. Something like this should work inside your loop (untested):
var line = reader.ReadLine();
var values = line.Split(',');
itemlist.Add(new item { stallnumber = Convert.ToInt32(values[0]), ... });

Categories