Tool that auto-generate a code for accesing a xml-file - c#

My application have a configuration xml-file. That file contains more than 50 program settings. At the present time I read and save each program setting separately. I guess It is not effiсiently for such tasks.
I need something that can auto-generate a code for load and save my program settings using predefined xml-schema.
I found a dataset in Add New Item dialog. Unfortunately, i cannot add new code to dataset1 such as events in set-accessors of properties because of this
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
Maybe, there is a tool that allows a user to generate a wrapper for accesing a xml-file ? Such as DataSet1, but with availability to add events.
Edit: I didn't mark a useful answer because i read an articles (link) which you give me. I will mark useful answer later.

If you are not willing to use app.config/web.config or the properties file (which Oded and Bruno recommend and I recommend as well), I highly recommend this utility:
Web Services Contract First (WSCF) Blue for VS2008 and VS2010
If you're on VS2005, you'll want this version of the tool: http://www.thinktecture.com/resourcearchive/tools-and-software/wscf (don't use the VS2008 version on this site. I could never get it to work right.)
Once you have the plugin installed into Visual Studio, you'll need an XSD schema of your XML file. (Google for an online XSD Generator.) Following the instructions found on the WSCF website, you can generate a wrapper class that will deserialize and reserialize your XML and give you an abstracted view of your XML.
I figure it is impossible (or at least very hard) to add new node/element TYPES, but adding new instances of existing node/element types, accessing to your data, editing the data, reordering nodes, and then saving back out are all easy.
Deserialization code looks like this:
private MyGeneratedXMLconfigClass config;
using (StreamReader sr = new StreamReader(filename))
{
XmlSerializer cXml = new XmlSerializer(typeof(MyGeneratedXMLconfigClass));
config = (MyGeneratedXMLconfigClass)cXml.Deserialize(sr);
}
Now your XML has been de-serialized into the "config" instance of your custom class. Then you can access the whole class as a series of nested values and Lists.
For example:
string errorFile = config.errorsFile;
List<string> actions = config.actionList;
var specialActions = from action in config.actionList
where action.contains("special")
select action;
Etc., etc. Then once you're done manipulating your data, you can re-serialize with this code:
using (StreamWriter wr = new StreamWriter(filename, false))
{
XmlSerializer cXml = new XmlSerializer(typeof(MyGeneratedXMLconfigClass));
cXml.Serialize(wr, config);
}
One of the very nice things about this tool is that it auto-generates all classes as "partial" classes, so that you can feel free to extend each class on your own without fear of your code getting stomped on in case you ever need to re-generate because the XSD/XML was changed.
I imagine this might sound like a lot, but the learning curve is actually pretty easy and once you get it installed and working, you'll realize how stupidly easy it is. It's worth it. I swear. :-)

If you have an appropriate xsd schema for your xml file microsoft provides xsd.exe, a small tool which auto-generates c# classes for this schema.
For details see: http://msdn.microsoft.com/en-us/library/x6c1kb0s%28VS.71%29.aspx

Why are you using hand rolled XML for configuration? What is wrong with the existing app.config and web.config schemas?

Why not use a .Settings file?

You can follow these steps:
1) generate an XSD file from your XML file. For There used to be a tool to infer schema from an XML file, I forgot what it's called. Currently I use my own utility, which basically runs this core routine to read an xml file and generate the corresponding xsd:
static void InferSchema(string fileName)
{
XmlWriter writer = null;
XmlSchemaInference infer = new XmlSchemaInference();
XmlSchemaSet sc = new XmlSchemaSet();
string outputXsd = fileName.Replace(".xml", ".xsd");
sc = infer.InferSchema(new XmlTextReader(fileName));
using (writer = XmlWriter.Create(new StreamWriter(outputXsd)))
{
foreach(XmlSchema schema in sc.Schemas())
{
schema.Write(writer);
Console.WriteLine(">> found schema - generated to {0}",
outputXsd);
}
}
}
2) run xsd.exe to generate a serializable class from the XSD file.
xsd.exe /c /n:MyNameSpaceHere MyGenerated.xsd
Next, you can read the XML file into the serializable class using XmlSerializer.Serialize() method. Something like this:
public static void Serialize<T>(T data, TextWriter writer)
{
try
{
XmlSerializer xs = new XmlSerializer(typeof(T));
xs.Serialize(writer, data);
}
catch (Exception e)
{
throw;
}
}
Finally, you can write back to the XML file from the class using the XmlSerializer.Deserialize() method, like this for instance:
public static void Deserialize<T>(out T data, XmlReader reader)
{
try
{
XmlSerializer xs = new XmlSerializer(typeof(T));
data = (T)xs.Deserialize(reader);
}
catch (Exception e)
{
reader.Close();
throw;
}
}

This is called a properties file. C# should have something similar to Java's Properties class where you can load all properties without hard-coding their names.
EDIT:
There's apparently no built-in properties parsing solution for C#. But you can easily implement your own. See here.

If you have an XSD file, you can generate classes from that. Besides the already mentioned xsd.exe from Microsoft (which hasn't been updated for quite some time), there are other tools for this. I am using XSD2Code, which allows generating strongly typed collections, lazy initialization, etc.
If you do not have an XSD, you can point the xsd.exe at your xml-file, and it will generate an XSD from that. The schema usually needs some work, but generally is a good starting point.
xsd.exe (instance).xml

You can use System.Xml.Serialization - it's very easy and you can serialize even class objects directly, like MyCustomClass (it even saves MyCustomClass public fields).
Deserializing the XML file will get a new instance of MyCustomClass, so such a feature is priceless.
Note one thing: you should add EVERY SINGLE TYPE you use in the class, but that's easy though.
I attached a complete project that does the thing you want. just change classes and objects and that will be all.
source code
for example (i'm shortening the code):
using System.Xml;
using System.Xml.Serialization;
using System.IO;
[XmlRootAttribute("Vendor")]
class Vendor{
[XmlAttribute]
Product prod;
}
[XmlRootAttribute("Product")]
class Product{
[XmlAttribute]
public string name="";
}
class Test{
Vendor v=new Vendor();
Product p=new Product();
p.name="a cake";
v.prod=p;
//add EVERY SINGLE TYPE you use in the serialized class.
Type[] type_list = { typeof(Product) };
XmlSerializer packer = new XmlSerializer(v.GetType(),type_list);
XmlWriter flusher = XmlWriter.Create(#"c:\bak.xml");
packer.Serialize(flusher, v);
flusher.Close();
XmlReader restorer = XmlReader.Create(#"c:\bak.xml");
Vendor v2 = (Vendor)packer.Deserialize(restorer);
//v2.prod.name is now "cake"
//COOL was my first impression :P
}

Related

How to parse .proto file into a FileDescriptor in C#?

My goal is exactly the same as stated in this issue on github:
how to read an existing .proto file and get a FileDescriptor from it
I cannot use the suggested "workaround", for 2 reasons:
I have "plain" .proto files, i.e.:
they are text files, just like good old addressbook.proto
they are not self-describing
I do not want to invoke the protoc compiler as an external application.
According to Marc this is possible with protobuf-net library:
Without a compiled schema, you would need a runtime .proto parser. [...] protobuf-net includes one (protobuf-net.Reflection)
I found Parsers.cs
Thanks Marc, but how do I use/do this?
Is this the right entry point?
Is there a minimal working example somewhere?
var set = new FileDescriptorSet();
set.Add("my.proto", true);
set.Process();
That's all you need; note that if you want to provide the actual contents (rather than having the library do the file access), there is an optional TextReader parameter. If you need imports:
set.AddImportPath(...);
Once you've called Process, the .Files should be populated along with the .MessageTypes of each file, etc.
For a more complete example:
var http = new HttpClient();
var proto = await http.GetStringAsync(
"https://raw.githubusercontent.com/protocolbuffers/protobuf/master/examples/addressbook.proto");
var fds = new FileDescriptorSet();
fds.Add("addressbook.proto", true, new StringReader(proto));
fds.Process();
var errors = fds.GetErrors();
Console.WriteLine($"Errors: {errors.Length}");
foreach(var file in fds.Files)
{
Console.WriteLine();
Console.WriteLine(file.Name);
foreach (var topLevelMessage in file.MessageTypes)
{
Console.WriteLine($"{topLevelMessage.Name} has {topLevelMessage.Fields.Count} fields");
}
}
Which outputs:
addressbook.proto
Person has 5 fields
AddressBook has 1 fields
google/protobuf/timestamp.proto
Timestamp has 2 fields
Notice that you didn't have to provide timestamp.proto or an import path for it - the library embeds a number of the common imports, and makes them available automatically.
(each file is a FileDescriptorProto; the group of files in a logical parse operation is the FileDescriptorSet - which is the root object used from descriptor.proto; note that all of the objects in this graph are also protobuf serializable, if you need a compiled/binary schema)

How to init Configuration Object from XML? [duplicate]

I'm trying to unit test a custom ConfigurationSection I've written, and I'd like to load some arbitrary configuration XML into a System.Configuration.Configuration for each test (rather than put the test configuration xml in the Tests.dll.config file. That is, I'd like to do something like this:
Configuration testConfig = new Configuration("<?xml version=\"1.0\"?><configuration>...</configuration>");
MyCustomConfigSection section = testConfig.GetSection("mycustomconfigsection");
Assert.That(section != null);
However, it looks like ConfigurationManager will only give you Configuration instances that are associated with an EXE file or a machine config. Is there a way to load arbitrary XML into a Configuration instance?
There is actually a way I've discovered....
You need to define a new class inheriting from your original configuration section as follows:
public class MyXmlCustomConfigSection : MyCustomConfigSection
{
public MyXmlCustomConfigSection (string configXml)
{
XmlTextReader reader = new XmlTextReader(new StringReader(configXml));
DeserializeSection(reader);
}
}
You can then instantiate your ConfigurationSection object as follows:
string configXml = "<?xml version=\"1.0\"?><configuration>...</configuration>";
MyCustomConfigSection config = new MyXmlCustomConfigSection(configXml);
Hope it helps someone :-)
I think what you're looking for is ConfigurationManager.OpenMappedExeConfiguration
It allows you to open a configuration file that you specify with a file path (wrapped inside a ExeConfigurationFileMap)
If what the other poster said is true, and you don't wish to create a whole new XML file for testing, then I'd recommend you put your Configuration edits in the Test method itself, then run your tests against the freshly changed configuration data.
Looking at the members of the class, I'd say the answer is probably no*. I'm not sure why you'd want to do this anyway, rather than create your own XML configuration file.
*That's no, excluding messy reflection hacks

How to create a component by providing the XML source file as input

I want to create a component by giving XML source input directly using core service 2011, in SDL Tridion 2011.
I want to write code to create a component by uploading source XML. Using the core service 2011.
Say name of the xml file is helloworld.xml and location is D:\abcd\cdef\all\helloworld.xml.
I have written the code like this, but its not working.
XmlDocument contentxml = new XmlDocument();
contentxml.LoadXml(#"D:\abcd\cdef\all\helloworld.xml");
Response.Write("<BR>" + contentxml.ToString());
component.Content = contentxml.ToString();
ComponentData comp = (ComponentData)client.Create(component, new ReadOptions());
The Response.write is displaying nothing. Correct me if I missed any thing.
It's not creating any component and error is coming.
When i tried this:
XmlDocument contentxml = new XmlDocument();
try
{
contentxml.LoadXml(#"D:\abcd\cdef\all\helloworld.xml");
}
catch (XmlException exp)
{
Console.WriteLine(exp.Message);
}
StringWriter sw = new StringWriter();
XmlTextWriter xw = new XmlTextWriter(sw);
contentxml.WriteTo(xw);
Response.Write("<BR>" + sw.ToString());
component.Content = sw.ToString();
ComponentData comp = (ComponentData)client.Create(component, new ReadOptions());
This time it's showing unable to find UUId: some thing like that.
My helloworld.xml looks like this.
<Content xmlns="uuid:1111eb85-0X11-11f9-1e2X-1X82X78fX920">
<first>Hello World.This is Fisrt field</first>
<second>Hello World.This is second field</second>
</Content>
It would be great if some one share some sample code to do it.
Loading any XML from a a file and trying to create a component won't work unless the XML uses the format the CMS is expecting.
The XML structure of a component in SDL Tridion has some fixed parts (Example Nodes Content, Metadata) plus some flexible parts
(The way you define the fields).
First you need to have the XML with the same structure that the CMS is expecting.
Typically the nodes that should be in your xml are the CONTENT and METADATA, load those in an XML Document and use the Core Service API to
create a component using the content contained in those nodes.
The best way to know how which is the structure of a component based on an schema is to create a sample component using the Tridion UI and
see how the XML is constructed. After that you need to create your XML Sources using that structure.
I posted recently an example of how to create a component using the Core Service, please have a look at that.
Faulted State error while creating component with Core Service
Following this code, you can access the nodes Content and Metadata
componentData.Content = xmlUtil.GetNewXmlNode("Content", schemaData.NamespaceUri);
componentData.Metadata = xmlUtil.GetNewXmlNode("Metadata", schemaData.NamespaceUri);
And replace those with your content
The general outline:
Load the XML from the file into an XDocument / XmlDocument.
Create a new Component by calling GetDefaultData on the client.
Set the Content property of the Component to the XML.
Save the Component by calling Save on the client.
If you haven't already, please have a look at the Core Service API documentation available on SDL Tridion World.
If you have trouble implementing this, please post the code that you have and what you have tried in order to make it work.
Using XmlDocument.LoadXML() expects an XML string as input, as commented by Peter you should use XMLDocument.Load() instead, see here for more details http://msdn.microsoft.com/en-us/library/a8ta6tz4.aspx
When you have passed that hurdle you will need the information Miguel gave in his answer to continue.

How to Parse XML in C#

I have managed to read in a saved .csv file on my hard disc and get the data to poputlate a data table. I now want to take that data and put it into XML format, then send the XML to a web service. How can I do this?
Thanks for your time.
One option would be to connect to the Web Service using WCF (or ASP.NET Web Services depending on which .NET version you're using). You can then easily fill the proxy classes the framework creates for you and call the service.
The second option would be to use an XmlTextWriter and use that to build the XML document in a MemoryStream. Once you have the XML document built in memory, you can flush the document and send it out to the Web Service.
A third option would be to use LINQ to XML to build the XML document on the fly. Depending on the structure you parse your CSV file into this may be easier/harder for you than using the XmlTextWriter.
XLinq is excellent for putting the data into XML. If you can use an up to date .NET framework I highly recommend it.
There's some info to get started with here (for example)
http://www.c-sharpcorner.com/UploadFile/mahesh/xLinkDoc06202007130827PM/xLinkDoc.aspx
As for sending that XML to a web service, perhaps you should be calling the web service via a client automatically generated using the Visual Studio ServiceReference tool.
You may or may not need to send XML to that -- in many cases services are object-based (i.e. you'd not need XLinq, provided you can parse the CSV into the correct objects.)
/EDIT:
Rough example for calling webservices using WCF:
using(var client = new ServiceReference1.ThirdPartyServiceClient())
{
client.SendSomething("123", "hello");
string output = client.GetSomething();
Console.WriteLine(output);
}
Following code can also be used.
public static List<Student> convertXMLtoList(string filePath)
{
XDocument doc = XDocument.Load(filePath);
List<Student> studentsMarks = doc.Descendants("Student").Select(x => new Student()
{
RollNo = int.Parse(x.Element("roll_no").Value),
Name = x.Element("name").Value,
}).ToList();
return studentsMarks;
}
Where XML looks like
<?xml version="1.0" encoding="utf-8"?>
<Students>
<Student>
<roll_no>1</roll_no>
<name>XYZ</name>
</Student>
...
</Students>
You can find more details at http://bit.ly/1eveLz3. you can find CSV to XML also on this post.
I haven't done this with a datatable, but it work great for other objects.
Try something like this:
public void writeToXML(DataTable inputData, string fileName) {
XmlSerializer xml = new XmlSerializer(typeof(DataTable));
StreamWriter sw = new StreamWriter(fileName);
xml.Serialize(sw, inputData);
sw.Close();
}
Edit: Just noticed you needed to pass it along to a web service. So instead of StreamWriter, use a memory stream...but same idea.
There are different options depending on how robust of a solution you want. Assuming you want to follow the quickest route you should look at the XmlWriter. Using an XmlWriter you can quickly generate an XML document, save to string and then pass along to your web service.

Trouble with XML Deserialization into XSD generated classes

I have a rather detailed xml file. Below is the top level nodes (I have included the ellipse as the lower level nodes are all well formed and properly filled with data):
<?xml version="1.0" encoding="UTF-8"?>
<config>
<Models>...</Models>
<Data>...</Data>
</config>
I have created an xsd file from using the Visual Studio 2008 command prompt:
xsd sample.xml
This generates the xsd file just fine. I then auto generate classes from the xsd with the command:
xsd sample.xsd /classes
For the deserialization of the xml file into a class object, I'm using the read function in the helper class:
public class XmlSerializerHelper<T>
{
public Type _type;
public XmlSerializerHelper()
{
_type = typeof(T);
}
public void Save(string path, object obj)
{
using (TextWriter textWriter = new StreamWriter(path))
{
XmlSerializer serializer = new XmlSerializer(_type);
serializer.Serialize(textWriter, obj);
}
}
public T Read(string path)
{
T result;
using (TextReader textReader = new StreamReader(path))
{
XmlSerializer deserializer = new XmlSerializer(_type);
result = (T)deserializer.Deserialize(textReader);
}
return result;
}
}
When attempting the deserialization with:
var helper = new XmlSerializerHelper<configModels>();
var obj = new configModels();
obj = helper.Read(filepath);
I receive an error that I have deduced is because the deserializer is looking for the 'Models' node but the corresponding class name was generated as a combination of the root node and the 'Model' node (configModels). Why are the class names generated like this?
I tried to deserialize from the top node using:
var helper = new XmlSerializerHelper<config>();
var obj = new config();
obj = helper.Read(filepath);
Unfortunately, this the results in a slew of errors like the following:
System.InvalidOperationException was unhandled by user code
Message="Unable to generate a temporary class (result=1).
error CS0030: Cannot convert type 'Application.Lease[]' to 'Application.Lease'
error CS0030: Cannot convert type 'Application.CashFlow[]' to 'Application.CashFlow'
...ect.
Can somebody steer me towards what I might be doing wrong with my xsd auto-generating?
XSD.EXE is a good start - but it's far from perfect. Also, based on the XML you provided, XSD.EXE can't always decide for sure whether something is a single instance of an object, or an open-ended array of objects.
This seems to be the case for your two elements - Application.Lease and Application.CashFlow. How are they defined in the generated XSD file? Does that make sense to you? Quite possibly, you'd have to add a little hints, such as:
<xs:element name="Lease" minOccurs="0" maxOccurs="1" />
for an optional property, that's zero or one occurences only. Things like that are really hard for the xsd.exe tool to figure out based on just a single XML sample file.
Marc
Go to your generated class and change all from [][] ---> []
There's an issue with xsd.exe and lists. You have to go into the generated class and manually edit the file to the correct type. I've switched to using Xsd2Code. So far it doesn't seem to have this problem.
Another issue that can cause this problem is that the xml file contents between the tags (meaning the content) is still encoded when it shouldn't be. For example, the <br> tags in my content were still <br> instead of <br />. The xsd generator turned these into elements in the schema then mislabeled them as unbounded since there was more than one found. Unencoding them fixed the problem and generated the classes correctly.

Categories