I have searched for a bit now, but i'm not able to find a way to autogenerate data from a XML Schema programmatically. Lets say I have this XML schema:
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" name ="Persons">
<xs:complexType>
<xs:sequence>
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
I am able to create a XML from this using the VS function "Generate Sample XML"
Is there a way to do this programmatically?
Edit: To specify. I do not want to create all the objects and insert data programmatically myself. I would like for it to create the objects and attributes automatically just like the "Generate Sample XML" in VS. The reason for this is that i would like to change the XSD without having to do anything about xml sample generation.
after doing some searching. I have found a project that have implemented a xml sample generator. I created a test solution and imported the classes. Then i deleted the XmlGen.cs file and created my own main method. The output will be based on the root element.
public static void Main(string[] args)
{
using (var stream = new MemoryStream(File.ReadAllBytes("schema.xsd")))
{
var schema = XmlSchema.Read(XmlReader.Create(stream ), null);
var gen = new XmlSampleGenerator(schema, new XmlQualifiedName("rootElement"));
gen.WriteXml(XmlWriter.Create(#"c:\temp\autogen.xml"));
Console.WriteLine("Autogenerated file is here : c:\temp\autogen.xml");
}
}
You can write simple function for put 1 row into your data table and after that execute DataTable.WriteXml(string filePath)
Somethig like that:
xmlschema1 schema=new xmlschema1();
//put some test data in table
schema.Persons.AddPersonsRow(...some params);
//generate xml
schema.Persons.WriteXml(filePath);
Related
I need to give support for an old project and i dont have much experince with xsd .
Project run xsd.exe on DataSet.xsd file and generate DataSet.cs file which include genarated c# classes.
I need a flag or attribute on properties of genarated classes .I add a new attribute to xsd file with name "intradaySupport" .And i try both as attribute and annotation as in figure below but generated class in DataSet.cs have noting with "intradaySupport".
How should i update my DataSet.xsd file so final genarated classes have marked with a flag or attribute.
Full of content atached on link just put content to files stated and run xsd
CDBDataSet.xsd
https://pastebin.com/e0DPAxgb
CustomFields.xsd
https://pastebin.com/ScS3whrY
enter code here
If you want to create an attribute in your xsd you have to specify a <xs:attribute name="intradaySupport" type="xs:boolean" use="required"/> in your xsd. It should be located just after the xs:sequence:
<xs:element name="AccountType">
<xs:complexType>
<xs:sequence>
<xs:element name="Account_x0020_type" type="string12" minOccurs="0" />
<xs:element name="Description" type="string40" minOccurs="0" >
...
<xs:element name="Not_x0020_used" type="string1" minOccurs="0" />
</xs:sequence>
<xs:attribute name="intradaySupport" type="xs:boolean" use="required"/>
</xs:complexType>
</xs:element>
...
using xsd.exe /dataset it will generate a boolean column columnintradaySupport in your data set:
[global::System.Serializable()]
[global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedTableSchema")]
public partial class AccountTypeDataTable : global::System.Data.DataTable, global::System.Collections.IEnumerable {
private global::System.Data.DataColumn columnintradaySupport;
private global::System.Data.DataColumn columnAccount_type;
...
}
This is an example of an XSD for one of the templates that will be stored in the database. The "to_email", "first_name" etc are all tokens and I need to dynamically create a dictionary or an object that can be returned to the client that will give a list of these tokens. The idea behind this is if there is any change in a template then we will just insert another value in the database and it should automatically be created dynamically for returning it to client when they will query for this template.
How do I go about creating/parsing this?
I don't want create a class object with individual element as that would mean that I will have to change it for every addition of the elements. So it has to be something generic.
We should be able to return the set as JSON or XML based on what the client asks for.
How do I go about doing this?
Any help would be appreciated.
Thank you in advance.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd"
xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="claim">
<xs:complexType>
<xs:sequence>
<xs:element name="to_email" type="xs:string"/>
<xs:element name="first_name" type="xs:string"/>
<xs:element name="last_name" type="xs:string"/>
<xs:element name="url" type="xs:string"/>
<xs:element name="received_date" type="xs:date"/>
<xs:element name="contact_number" type="xs:string"/>
<xs:element name="employer_name" type="xs:string"/>
<xs:element name="er_label" type="xs:string"/>
<xs:element name="er_flag" type="xs:integer"/>
<xs:element name="benefit_id" type="xs:integer"/>
<xs:element name="employee_id" type="xs:integer"/>
<xs:element name="employer_id" type="xs:integer"/>
<xs:element name="form_id" type="xs:integer"/>
<xs:element name="er_url" type="xs:string"/>
<xs:element name="tax" type="xs:string"/>
<xs:element name="Repeater" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="form_id" type="xs:integer"/>
<xs:element name="amount" type="xs:integer"/>
<xs:element name="expense_name" type="xs:string"/>
<xs:element name="date_of_service" type="xs:string"/>
<xs:element name="status_of_claim" type="xs:string"/>
<xs:element name="status_reason"/>
<xs:element name="Order_by" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Adding further comments:
The response to the client should be something like each property of the object representing a field. For example a object.
{
‘field1’: <FieldDefinition>
‘field2’: <FieldDefinition>
‘field3’: <FieldDefinition>
.
.
.
}
The object would contains the following properties like Type for example if it is a string or int, Display name i.e. the internal name could be first_name but the display name would FirstName# etc.
Also the could be an array as well. So this makes it little more complex.
Am I making any sense?
I believe you can do the XML processing or you can find that in Google. Plenty of examples are there. I just added the code for logic you have mentioned for the properties. //Your XML processing
var fields = new List<FieldDefinition>
{
new FieldDefinition{ Type="string", DisplayName="FirstName"},
new FieldDefinition{ Type="int", DisplayName="EmployeeId"}
};
var infr = new List<Infrastructure>
{
new Infrastructure { def1=fields.FirstOrDefault()}// loop through to assign each item
};
foreach (var item in infr)
Console.WriteLine(item.def1.DisplayName + " -" + item.def1.Type);
Console.Read();
}
}
public class Infrastructure
{
public FieldDefinition def1 { get; set; }
}
public class FieldDefinition
{
public string Type { get; set; }
public string DisplayName { get; set; }
}
You generate classes for them using the xsd.exe util
Seen here:
How to generate .NET 4.0 classes from xsd?
xsd your.xsd /classes
You can parse your template using XPath query or any generic XML processing. For any template change, you can opt for CacheDependency for File. You just cache the whole xml and if any changes to the tag/file then you insert that portion to the database and reload the cache. You can try SQLDependency also to get similar work.
Another option, you can go for filesystemwatcher which will raise event for changing in the file content. Then you just need to insert the added portion in the database.
I have searched for a bit now, but i'm not able to find a way to autogenerate data from a XML Schema programmatically. Lets say I have this XML schema:
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" name ="Persons">
<xs:complexType>
<xs:sequence>
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
I am able to create a XML from this using the VS function "Generate Sample XML"
Is there a way to do this programmatically?
Edit: To specify. I do not want to create all the objects and insert data programmatically myself. I would like for it to create the objects and attributes automatically just like the "Generate Sample XML" in VS. The reason for this is that i would like to change the XSD without having to do anything about xml sample generation.
after doing some searching. I have found a project that have implemented a xml sample generator. I created a test solution and imported the classes. Then i deleted the XmlGen.cs file and created my own main method. The output will be based on the root element.
public static void Main(string[] args)
{
using (var stream = new MemoryStream(File.ReadAllBytes("schema.xsd")))
{
var schema = XmlSchema.Read(XmlReader.Create(stream ), null);
var gen = new XmlSampleGenerator(schema, new XmlQualifiedName("rootElement"));
gen.WriteXml(XmlWriter.Create(#"c:\temp\autogen.xml"));
Console.WriteLine("Autogenerated file is here : c:\temp\autogen.xml");
}
}
You can write simple function for put 1 row into your data table and after that execute DataTable.WriteXml(string filePath)
Somethig like that:
xmlschema1 schema=new xmlschema1();
//put some test data in table
schema.Persons.AddPersonsRow(...some params);
//generate xml
schema.Persons.WriteXml(filePath);
I have one XML File:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" <xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="UsersPreferenceSettingsDT">
<xs:complexType>
<xs:sequence>
<xs:element name="USERPROFILEID" type="xs:int" minOccurs="0" />
<xs:element name="SCREENAMEID" type="xs:int" minOccurs="0" />
<xs:element name="FREEZEDCOLUMNID" type="xs:string" minOccurs="0" />
<xs:element name="ORDEROFCOLUMNS" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<UsersPreferenceSettingsDT>
<USERPROFILEID>219</USERPROFILEID>
<SCREENAMEID>1</SCREENAMEID>
<FREEZEDCOLUMNID>2|3|4|5</FREEZEDCOLUMNID>
<ORDEROFCOLUMNS>1</ORDEROFCOLUMNS>
</UsersPreferenceSettingsDT>
<UsersPreferenceSettingsDT>
<USERPROFILEID>123</USERPROFILEID>
<SCREENAMEID></SCREENAMEID>
<FREEZEDCOLUMNID>s|s|s</FREEZEDCOLUMNID>
<ORDEROFCOLUMNS></ORDEROFCOLUMNS>
</UsersPreferenceSettingsDT>
</NewDataSet>
In that i have to update the XML Element (i,e USERPROFILeID =219, USERPROFILEID is Unique). At same time another user also update the same XML file but different XML element (i,e USERPROFILEID=123). How can the XML reflect the both users XML update(Like SQL or ORACLE DB Update). I used the following code to update.
userPreferenceSettingsDS.WriteXml(userPreferenceSettingsXMLFilePath, XmlWriteMode.WriteSchema);
but it reflect the last user profile update Value only , while multiple user simultaneously update the XML. Anyone guide me to come out of these issue?
Well, being that we are talking about an xml file and not a database you will not be able to get the "latest" version of the data unless you always load from file and not from memory but even then you expose yourself to concurrency issues.
The best choice here would be to switch to a database or maybe implement something like a Singleton Repository that would serve all users and that way you will always return the latest values of the data in the xml.
And it would fix your other issue, when you write to file you will write the "merged" version of the data that will contain changes from multiple users.
Resources for XML as database:
http://social.msdn.microsoft.com/Forums/en/sqldataaccess/thread/346a2816-faae-461d-aaa8-235d9c0dd55c
XML Database in C#.net
http://bytes.com/topic/c-sharp/answers/460625-c-pure-xml-database
Or use a single profile file per user.
You would need to ensure that only one save operation can happen at a time.
To do this, you need to provide a static (shared) class that reads from and writes to the file. The fancy new buzzword for this is a Singleton instance, but it's simply the following:
public static class MyXMLAccessor
{
public static void saveTheData()
{
//this method would write the data to the XML file and save it.
}
public static string ReadTheData()
{
//to read the data from the file
}
}
This way, you're guaranteed that the result of one operation is saved before the next operation is started.
A more complex solution would be to read the xml into an application-scope dataset so that it can act like a database. You would then periodically write the contents of the dataset back to a file using the DataSet.ToXML() method.
It sounds to me as if you should be using an XML database. The sooner you make the move, the more benefit you will get from it, and the less you will spend on creating your own inadequate home-grown solution.
I am trying to create a waypoint generator using windows forms, that allows a user to create waypoint & path data via a GUI & output the data to an XML file. I've chosen to take advantage of the built in c# XML serialization feature, but have been unable to format the XML output in the way required by the client.
A stripped version of the waypoint data object would look something like the following:
// Waypoint data class
[XmlRoot("RootNode")]
public class WaypointProjectData
{
[XmlElement("Map")] // Also tried to use XmlElementAttribute,
[XmlAttribute("file")] // XmlAttributeAttribute, and many variations
// of these qualifiers, with no success
public string m_szMapImageFileName;
[XmlAttribute("width")]
public int m_iWidth;
[XmlAttribute("height")]
public int m_iHeight;
[XmlArray("Nodes")]
public ArrayList m_aoNodes;
WaypointProjectData()
{
m_szMapImageFileName = "map.png";
m_aoNodes = new ArrayList();
}
}
The client requires that the XML output conforms with the following layout/format:
<RootNode>
<Map file="map.png" width="100" height="100" />
<OtherData var="variable" data="10" />
<Nodes>
<Node x="10" y="30" />
<Node x="30" y="20" /> // etc...
</Nodes>
</RootNode>
Some clear examples on how to do this using c# xml serialization would be very helpful. Thanks!
When I have to serialize something in a specific Xml format like this, I start with a schema (inferred if necessary, hand-crafted if known). Then I use the VS xsd tool to create the serialization classes (and yes, I know xsd can be used for the inferring schema part—I just never bother with it for that purpose).
So if you have an xsd file like this one created from your example (note that I specified data types as much as possible—this helps the xsd tool to use the appropriate types for properties):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="RootNode">
<xs:complexType>
<xs:sequence>
<xs:element name="Map">
<xs:complexType>
<xs:attribute name="file" type="xs:string"/>
<xs:attribute name="width" type="xs:decimal"/>
<xs:attribute name="height" type="xs:decimal"/>
</xs:complexType>
</xs:element>
<xs:element name="OtherData">
<xs:complexType>
<xs:attribute name="var" type="xs:string"/>
<xs:attribute name="data" type="xs:decimal"/>
</xs:complexType>
</xs:element>
<xs:element name="Nodes" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="Node" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="x" type="xs:decimal"/>
<xs:attribute name="y" type="xs:decimal"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
If you name this Root.xsd, then you can go to the VS command line and run
xsd Root.xsd /c /n:myProject.Xml
That'll create a class file (named Root.cs because that's the default when processing Root.xsd) that contains objects you can easily plug into .Net to serialize and deserialize the XML. Note that I specified the namespace the classes will have ("/n:myProject.Xml"). I prefer to control that namespace, but defaults are usually fine for the rest. Further, the tool creates partial classes, so if you want custom property accessors, you're fine to add them in a separate file that won't get creamed if you need to run the tool again.
Another tip, I create a text file in my project with the name "<xsd name> xsd Command Line.txt". That way I just have to paste that into the VS command line and don't have to remember everything else I used.
As soon as you go off the beaten track serialisation is a huge PIA.
You need something to mark up as map, probably OtherData as well, so that means you need a class or struct that corresponds to the node.
e.g. WaypointProejctdata as a class Map, that has properties filename, width and height.
My general rule of thumb, is as soon as I have to start messing with my objects to get the xml, serialisation gets binned,and I add an interface that takes an XmlReader or Writer and implement it.
Tryng to get serialisation to do what you want is usually way more code and far less comprehensible than doing that.