So I am developing an application that I want to be able to dynamically parse an xml file, grab attributes and populate a form that is created based on what elements are present in the xml file. Then the values can be edited, and written back to the xml file that was originally opened.
I've been able to parse, save values to a database , populate forms, and write back to the original xml file via hard coding, and I think I have an idea for the dynamic "database" structure (a dictionary where the key is a node's name, and the value is a dictionary if I wanna store a node's child node information, or a string if I'm in the furthest nested child node of an element).
I'm stuck on how to grab the information I need and how to store it in the "database" structure I've come up with. I've done research and have seen people use the "dynamic" object and linq. But everything I've seen seems to involve knowing the path names they've needed before run time. Any ideas on how I should be going about actually parsing the file and grabbing data, first off? I think if I can get that figured out, the rest should kind of fall into place.
Say I have this xml
<users>
<user1 age="43">John Doe</user1>
<user2 age="40">Jane Doe</user2>
</users>
An example database setup would look like Dictionary<users, Dictionary<user1, Dictionary<name,John Doe>
Where you could go Key("users").Key("user1").Key("name").Value to get John Doe or something like that.
Any other suggestions for my database setup would also be appreciated
It sounds like what you are looking for is XML serialization. Before you can do that though, you need to simplify your xml. Instead of numbering the <user> elements, you will want to use an attribute that has the value for the user id. For example you can use an id attribute.
<users>
<user id="1" age="43">John Doe</user>
<user id="2" age="40">Jane Doe</user>
</users>
Once you have done this, create a class that you can serialize to this xml.
using System.Xml.Serialization;
[XmlRoot(ElementName = "users")]
public class Users : List<User>
{
}
[XmlType(TypeName = "user")]
public class User
{
[XmlAttribute(AttributeName = "id")]
public int Id { get; set; }
[XmlAttribute(AttributeName = "age")]
public int Age { get; set; }
[XmlText]
public string Name { get; set; }
}
Then all you have to do to load from the file is deserialize.
XmlSerializer serializer = new XmlSerializer(typeof(Users));
Users users = (Users)serializer.Deserialize(File.OpenRead("XMLFile1.xml"));
You can use LINQ to query the Users collection for specific users.
var user1 = users.Where(u => u.Id == 1)
Modify the User objects or add more to the Users collection, then serialize to save changes back to the file.
XmlSerializer serializer = new XmlSerializer(typeof(Users));
serializer.Serialize(File.OpenWrite("XMLFile1.xml"), users);
You could parse xml using XmlDocument class. After parsing you have tree of nodes which you can traverse and show in UI. I don't understand why you want to save xml as distinct records of values in database, just save it as text. Anyway for saving xml you should translate its records back to xml.
Related
I'm having the program shown below:
When the user selects a Client, and after specifying the date using the datePicker, the date should be added under the water request for the same user.
We might have more than one request for each client.
The structure of my XML file is as follows:
<clients>
<record>
<Name></Name>
<Surname></Surname>
<Mobile></Mobile>
<Address></Address>
<Request>
<date></date>
</Request>
</record>
</clients>
Can you help me with this one please?
I've walked through this example:
string xtitle = textBox1.Text.ToString();
XDocument xmlDoc = XDocument.Load("Book.xml");
XElement element =
xmlDoc.Root.Elements("book").Where(r => (string)r.Element("Isbn") == xtitle).FirstOrDefault();
if (element != null)
{
element.SetElementValue("Isbn", textBox1.Text);
element.SetElementValue("Book_Name", textBox2.Text);
element.SetElementValue("Price", textBox3.Text);
element.SetElementValue("Date_of_Publication", textBox4.Text);
element.SetElementValue("Number_of", textBox6.Text);
element.SetElementValue("Category", textBox7.Text);
}
xmlDoc.Save("Book.xml");
Supposing that "ISBN" has another subelement, how can I access it?
XDocument xmlDoc = XDocument.Load("Book.xml");
You can use Linq to Xml to get the Request element and add the date node to it.
var requestDate = DateTime.Today; //Get the date from the date picker
var requestElement = xEle.Descendants("Request").FirstOrDefault();
if(requestElement != null)
{
requestElement.Add(new XElement("date", requestDate));
xmlDoc.Save("Book.xml");
}
I think I would prefer to define the corresponding classes and objects and use an XML serializer constructed from them to read and save the file.
You would need to learn how to use the serializable interface. Look here. Using that, you will create classes to hold the data objects that you would read from the xml file. The structure of the classes will match the structure of your xml file, so that you will have a request class that just has a date property. You will also have a "Client" class that has a collection of request objects as one of its properties, along with client name, etc.
Using the outermost class, you will construct an xml serializer which you can then use to deserialize (read from text/xml file into actual objects in memory) and serialize the file (save from the objects in memory back to a text/xml file. This is just a couple of lines of code that you will find here.
In memory, you will have an array or a collection of Client objects. You can then use LINQ to mess with that collection - insert, sort, delete. You can bind your listbox to that collection to display its data.
Hope this helps.
I have seen various questions on this, but none seem to be working in my problem. I have an Umbraco site set up and it stores its page contents as XML in a database column. An example one is below:
Sorry for the screen grab and not the actual code, but the editor kept stripping things out.
What I would like to do ideally is either on the page in c#/Linq (have been trying to manipulate is from a string value) or within a SQL query. To be able to pull out the 'url-name', 'nodeName' and 'bodyText' fields.
Many thanks
Since the column is not defined as XML in the database, you can pull out the string and parse the text/string as an XML document:
// xml would be pulled from the DB
string xml = "<RunwayTextpage nodeName=\"Test page\" urlName=\"test-page\"><bodyText>Body Text</bodyText></RunwayTextpage>";
var doc = XDocument.Parse( xml );
string nodeName = doc.Root.Attribute( "nodeName" ).Value;
string urlName = doc.Root.Attribute( "urlName" ).Value;
string bodyText = doc.Root.Element( "bodyText" ).Value;
Another option would be to use string manipulation in the SQL query itself, but that would end up being much less maintainable whereas the above is easily understandable.
Why don't use uQuery? Don't really know your purposes, but it has a method called GetNodesByXPath that gets a collection of nodes or node from an XPath expression by querying the in memory xml cache.
It's more wise in terms of performance if your tree is large.
I have a long list of languages and their respective codes (http://pastebin.com/rn4JbTtP), which was generated by MP4Box.
I want to load this list into some sort of key-value store in C# (like a dictionary), so that the user will be able to select a language from a combo box and the program will return the respective language code.
Is there any way this can be done without reading the text file each time the program is run? If so, how?
UPDATE (as commented here): Sorry, I didn't explain myself clearly. I've got no problem with reading text files, it's just that the current format requires a lot of parsing before it can be fed into a Dictionary. What will be the best way to store these pairs so that it will require the least amount of parsing at runtime?
You will have to read the file anyway on the startup of your application.
One solution could be to create an xml file containing your languages like this:
<?xml version="1.0" encoding="utf-8" ?>
<Languages>
<Language Name="English" Code="en"/>
<Language Name="German" Code="de"/>
</Languages>
and you can also have a small class to hold the name and the code of the language like this:
class Language
{
public string Name { get; set; }
public string Code { get; set; }
}
and a reading method to read all languages:
private static List<Language> ReadLanguageFile()
{
List<Language> languages = new List<Language>();
string path = #"LanguagesFile.xml";
XDocument xdoc = XDocument.Load(path);
var lans = xdoc.Root.Elements("Language");
Language lan;
foreach (var item in lans)
{
lan = new Language();
lan.Name = item.Attribute("Name").Value;
lan.Code = item.Attribute("Code").Value;
languages.Add(lan);
}
return languages;
}
then you may bind your combo box data source to the language list like this:
cmb.DataSource = ReadLanguageFile();
cmb.DisplayMember="Name";
cmb.ValueMember="Code";
Now, if you don't want to create a file for languages you may create a class which keeps all your languages like this:
public sealed class Languages
{
public static List<Language> GetLanguages()
{
return new List<Language>
{
new Language{Code="en",Name="English"},
new Language{Code="de",Name="German"},
};
}
}
Is there any way this can be done without reading the text file each time the program is run?
Not really. The data needs to be loaded into memory somehow. As #lc commented, outside of hardcoding the dictionary into the application code, you will need to store it and read it.
You can store the data for reading in several ways, but it will need to be read into memory:
Save to a local text file
Serialize to a local file
Use an embedded database to store the data
Update:
Seeing as you want to load local data with minimum parsing, I suggest that once you have parsed the data into a dictionary, you serialize the dictionary to disk. When you deserialize from disk, you will have a populated instance of a dictionary.
I have a design related question. So please guide me on how to do this?
Right now, I have a xml structure which will be in this format.
<Sheet id="abc"/>
<Elements>
<Element id="xyz">
<value>23</value>
</Element>
<Element id="sdz">
<value>46</value>
</Element>
...
</Elements>
</Sheet>
So, we have a class like this to store each & every element of the sheet.
Sheet
{
Public string SheetId
{
get; set;
}
//all Elements will be stored in the below collection
Public IList<IDictionary<string, string>> Elements
{
get; set;
}
}
But now for few sheets the format has been changed to the below structure.
<abc> //SheetId
<Elements>
<Record>
<Element1/>
<Element2/>
<Element3/>
<Element4/>
</Record>
<Record>
<Element1/>
<Element2/>
<Element3/>
<Element4/>
</Record>
...
</abc>
So, we need to create a Generic class to hold the above xml formats and we don't want to have different object to store these.
I mean in future if we have some other xml format also we need to accommodate the same without any change in the Sheet class.
So, can you please advise me on how to design the Sheet Class.?
Ok. let me explain how my app works.
Actually we have around 200 sheets(in other words measures).
1) User will upload the sheet data in xml format (all sheets in xml file) & edit the same if they want Or Enter the data in the screen (dynamic screen generated using the xml template) if they dont want to upload.
2) Then the data will be stored in the Sheet object and it will go through lot of Validation process and finally the data will be converted to xml again and stored in the db.
You can ask why you want to store this as XML? The reason is we dont want to create 200 aspx pages for this same kind of data and thats why we are generating the sheet pages dynamically using the xml templates. Also, we will be adding, updating or deleting sheets frequently.
Ok. I think now you will have some idea about this issue.
To be more clear, all the elements in my XML file will be displayed as a field in the aspx page. It maybe a Textbox, dropdown & etc....
I would recommend designing your class based on what the information actually represents and how your software plans to utilize the data, not the XML format being used.
You should always be able to do the transposition from the data format into the structure which best represents how your program will use this data.
I have an XML file and I want to retrieve data from it so I can store this data in my database. I've searched and I found this post.
I don't know what the following means:
Create a XML schema so you can deserialize this XML into a .NET object - works best if you have tons of those files to import.
So:
I'd like to see some articles or examples of how to do this.
How do I check data that comes from an XML file?
This means that you can write a .NET object that reflects the structure of your XML file and then deserialize the XML file back to an instance of this object. For example if you have the following XML:
<User>
<FirstName>John</FirstName>
<LastName>John</LastName>
</User>
you could have a User class:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
and then deserialize:
var serializer = new XmlSerializer(typeof(User));
using (var reader = XmlReader.Create("test.xml"))
{
User user = (User)serializer.Deserialize(reader);
}
You can apply attributes to the .NET object in order to control the serialization/deserialization process.
As far as the validation of the XML file is concerned you could write a XSD schema (which is a XML file) representing the data structure of your file and then validate it against this schema. This will ensure that the XML file you have as an input obeys the defined rules (it has the correct node names, required properties, ...).
You want to know about "Create a XML schema so you can deserialize this XML into a .NET object - works best if you have tons of those files to import".
Here is the link that shows you how to achieve that:
Instructions
You can create schema using Visual studio. Just open XML file with VS. Then select XML->Create schema menu.
Or you can use Xsd.exe tool :
First extract shema using command
xsd.exe your.xml
Second generate
classes from generated schema using
command xsd.exe your.xsd /classes
And here you can find how to validate xml using xsd.