How should I write code in C# to create xml file like this
<ymaps:GeoObjectCollection>
<gml:name>Something</gml:name>
<gml:featureMembers>
<ymaps:GeoObject>
<gml:name>Something</gml:name>
<gml:description>Something</gml:description>
<gml:LineString>
<gml:pos>50.588298 55.145683</gml:pos>
<gml:pos>50.588290 55.145678</gml:pos>
<gml:pos>50.588288 55.145678</gml:pos>
</gml:LineString>
<ymaps:style>#customStyle1</ymaps:style>
</ymaps:GeoObject>
this yandex's xml file, and it has xsd file on http://maps.yandex.ru/schemas/ymaps/1.x/ymaps.xsd
First familiarize yourself with XML, XML Namespaces, XML Schemas and how to process XML data in .NET. Once you have mastered the basics, use the XML Schema Definition Tool (Xsd.exe) to generate classes from the XSD and use it from within your application.
Here is a demonstration of how to create the desired XML using LINQ to XML. I have created two classes to store the data: GeoObject and Pos:
var geoObjects = new[] {
new GeoObject {
Name = "Something",
Description = "Something",
Line = new[] {
new Pos { X = 50.588298M, Y = 55.145683M },
new Pos { X = 50.588290M, Y = 55.145678M },
new Pos { X = 50.588288M, Y = 55.145678M }
},
Style = "#customStyle1"
}
};
The XML is created using this code:
XNamespace ymaps = "http://maps.yandex.ru/ymaps/1.x";
XNamespace gml = "http://www.opengis.net/gml";
var xElement = new XElement(
ymaps + "GeoObjectCollection",
new XAttribute(XNamespace.Xmlns + "ymaps", ymaps),
new XAttribute(XNamespace.Xmlns + "gml", gml),
new XElement(gml + "name", "Something"),
new XElement(gml + "featureMembers",
geoObjects.Select(
geoObject => new XElement(
ymaps + "GeoObject",
new XElement(gml + "name", geoObject.Name),
new XElement(gml + "description", geoObject.Description),
new XElement(gml + "LineString",
geoObject.Line.Select(
pos => new XElement(
gml + "pos",
String.Format(CultureInfo.InvariantCulture, "{0} {1}", pos.X, pos.Y)
)
)
),
new XElement(ymaps + "style", geoObject.Style)
)
)
)
);
If you write out xElement you get the following XML:
<ymaps:GeoObjectCollection xmlns:ymaps="http://maps.yandex.ru/ymaps/1.x" xmlns:gml="http://www.opengis.net/gml">
<gml:name>Something</gml:name>
<gml:featureMembers>
<ymaps:GeoObject>
<gml:name>Something</gml:name>
<gml:description>Something</gml:description>
<gml:LineString>
<gml:pos>50.588298 55.145683</gml:pos>
<gml:pos>50.588290 55.145678</gml:pos>
<gml:pos>50.588288 55.145678</gml:pos>
</gml:LineString>
<ymaps:style>#customStyle1</ymaps:style>
</ymaps:GeoObject>
</gml:featureMembers>
</ymaps:GeoObjectCollection>
Related
I have the following code:
private string GetXmlBody()
{
XNamespace ns = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace xsdNs = "http://www.w3.org/2001/XMLSchema";
XNamespace xsiNs = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace outNs = "http://soap.sforce.com/2005/09/outbound";
XNamespace sfNs = "urn:sobject.enterprise.soap.sforce.com";
XDocument requestXml = new XDocument(
new XElement(ns + "Envelope", new XAttribute(XNamespace.Xmlns + "soapenv", ns), new XAttribute(XNamespace.Xmlns + "xsd", xsdNs), new XAttribute(XNamespace.Xmlns + "xsi", xsiNs),
new XElement(ns + "Body",
new XElement(outNs + "notifications", new XAttribute("xmlns", outNs),
new XElement(outNs + "OrganizationId", runInfo.OrgId),
new XElement(outNs + "SessionId", runInfo.SessionId),
new XElement(outNs + "EnterpriseUrl", runInfo.Location),
new XElement(outNs + "Notification",
new XElement(outNs + "Id", "04l0H000014TY73QAG"),
new XElement(outNs + "sObject", new XAttribute(XNamespace.Xmlns + "sf", sfNs), new XAttribute(xsiNs + "type", "sf:" + runInfo.RecordType),
new XElement(sfNs + "Id", runInfo.RecordId),
new XElement(sfNs + runInfo.Field, runInfo.FieldValue)
)
)
)
)
)
);
return requestXml.ToString();
}
Which will generate XML needed however I'm running into the following error:
System.Xml.XmlException : The ':' character, hexadecimal value 0x3A, cannot be included in a name.
due to the value of runInfo.FieldValue which contains :. For Example the value may look like:
Opportunity:006i000000sidsh;Account:;userId:a016S00000sjsiq;sandbox:true
So far all the solutions or similar problems that I've seen revolve around producing the correct element name, my problem is around the value. If for instance I remove the : from the runInfo.FieldValue variable then the expected XML is produced.
Any thoughts on how to get around this? I've tried URL encoding the string but that just leads to a similar error except it complains about % values.
I have the following code below. I am getting an error "the character ':' hexadecimal value 0x3A cannot be included in a name" Can anyone tell me how to fix this?
Thanks Below is the entire code
public static XDocument GenerateXMLSpreadSheet(DataTable tbl)
{
new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessing**Instruction("mso-application", "Excel.Sheet"),
new XElement("Workbook",
new XAttribute("xmlns", "urn:schemas-microsoft-com:office:spreadsheet"),
new XAttribute("xmlns:ss", "urn:schemas-microsoft-
com:office:spreadsheet"),
new XElement("Worksheet", new XAttribute("ss:Name",
tbl.TableName),
new XElement("Table", GetRows(tbl)
)
)
)
);
return xmlssDoc;
)
public static Object[] GetRows(DataTable tbl)
{
// generate XElement rows for each row in the database.
// generate from the bottom-up.
// start with the cells.
XElement[] rows = new XElement[tbl.Rows.Count];
int r = 0;
foreach (DataRow row in tbl.Rows)
{
// create the array of cells to add to the row:
XElement[] cells = new XElement[tbl.Columns.Count];
int c = 0;
foreach (DataColumn col in tbl.Columns)
{
cells[c++] =
new XElement("Cell",
new XElement("Data", new XAttribute("ss:Type", "String"),
new XText(row[col].ToString())));
}
rows[r++] = new XElement("Row", cells);
}
// return the array of rows.
return rows;
}
Basically, that's not how you handle namespaces in LINQ to XML. You never specify a string with a colon in - instead, you build up an XName from an XNamespace and a string.
The good news is that LINQ to XML handling of namespaces is simple. Here's a complete example:
using System;
using System.Xml.Linq;
public class Test
{
static void Main(string[] args)
{
XNamespace ns = "urn:schemas-microsoft-com:office:spreadsheet";
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessingInstruction("mso-application", "Excel.Sheet"),
new XElement(ns + "Workbook",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "ss", ns),
new XElement(ns + "Worksheet",
new XAttribute(ns + "Name", "my-table-name"),
new XElement(ns + "Table")
)
)
);
Console.WriteLine(doc);
}
}
Output (reformatted for clarity):
<?mso-application Excel.Sheet?>
<ss:Workbook
xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
<ss:Worksheet ss:Name="my-table-name">
<ss:Table />
</ss:Worksheet>
</ss:Workbook>
Note how you need to specify the namespace for all the elements and attributes.
Because you've specified an explicit prefix for the namespace, LINQ to XML uses it everywhere. If you remove this part:
new XAttribute(XNamespace.Xmlns + "ss", ns)
... then the namespace for elements will be defaulted, and LINQ to XML will generate a prefix for the attributes that need it explicitly specified (as attributes don't default their namespaces).
Then the output is (for example):
<?mso-application Excel.Sheet?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet">
<Worksheet p2:Name="my-table-name" xmlns:p2="urn:schemas-microsoft-com:office:spreadsheet">
<Table />
</Worksheet>
</Workbook>
The problem is how you defined namespaces.
To work with namespaces you may get one by calling XNamespace.Get("the namespace") and using this everywhere you want.
And for xmlns you may use static property XNamespace.Xmlns.
So the final code will look like:
new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XProcessingInstruction("mso-application", "Excel.Sheet"),
new XElement("Workbook",
new XAttribute("xmlns", ns),
new XAttribute(XNamespace.Xmlns + "ss", ns),
new XElement("Worksheet", new XAttribute(ns + "Name",
tbl.TableName),
new XElement("Table", GetRows(tbl)
)
)
)
);
I'm trying to create a fairly simple XML document that looks like this.
<?xml version="1.0" encoding="UTF-8"?>
<employees xmlns="http://website.com/xsd/MQ">
<employee>
<id>00122731</id>
<first-name>LUIS</first-name>
<last-name>GARCIA</last-name>
<subarea>4100</subarea>
<cost-center>904</cost-center>
<email-address>L.GARCIA#EMAIL.COM</email-address>
</employee>
</employees>
I was able to get the basics by using this code but I need to add the xmlns attribute and I'm not figuring out how to do that.
var xmlDoc = new XElement("employees",
from e in listEmployees
select new XElement("employee",
new XElement("id", e.EmployeeId),
new XElement("first-name", e.FirstName),
new XElement("last-name", e.LastName),
new XElement("subarea", e.SubArea),
new XElement("cost-center", e.CostCenter),
new XElement("email-address", e.EmailAddress)));
This is my attempt to add it but I get an error that this would cause and invalid structure.
XDocument xmlDoc = new XDocument(
new XElement("employees",
new XAttribute("xmlns", "http://website/xsd/MQ")),
from e in listEmployees
select new XElement("employee",
new XElement("id", e.EmployeeId),
new XElement("first-name", e.FirstName),
new XElement("last-name", e.LastName),
new XElement("subarea", e.SubArea),
new XElement("cost-center", e.CostCenter),
new XElement("email-address", e.EmailAddress))
);
UPDATE
Based on the link provided below this is what I came up with that worked.
XNamespace ns = "http://website/xsd/MQ";
var xmlDoc = new XElement(ns + "employees",
from e in listEmployees
select new XElement("employee",
new XElement("id", e.EmployeeId),
new XElement("first-name", e.FirstName),
new XElement("last-name", e.LastName),
new XElement("subarea", e.SubArea),
new XElement("cost-center", e.CostCenter),
new XElement("email-address", e.EmailAddress)));
You need to include the namespace on all of your elements, not just the top one:
XNamespace ns = "http://website/xsd/MQ";
var xmlDoc = new XElement(ns + "employees",
from e in listEmployees
select new XElement(ns + "employee",
new XElement(ns + "id", e.EmployeeId),
new XElement(ns + "first-name", e.FirstName),
new XElement(ns + "last-name", e.LastName),
new XElement(ns + "subarea", e.SubArea),
new XElement(ns + "cost-center", e.CostCenter),
new XElement(ns + "email-address", e.EmailAddress)
)
);
If that's too repetitive for you, you could make a convenience method:
XNamespace ns = "http://website/xsd/MQ";
private static XElement MQElement(string name, object contents)
{
return new XElement(ns + name, contents);
}
then use it:
var xmlDoc = MQElement("employees",
from e in listEmployees
select MQElement("employee",
MQElement("id", e.EmployeeId),
MQElement("first-name", e.FirstName),
MQElement("last-name", e.LastName),
MQElement("subarea", e.SubArea),
MQElement("cost-center", e.CostCenter),
MQElement("email-address", e.EmailAddress)
)
);
One more option to achieve same result is to construct XElement ignoring namespaces completely and then add them in separate code:
foreach (XElement e in xmlDoc.DescendantsAndSelf())
{
if (e.Name.Namespace == "")
{
e.Name = ns + e.Name.LocalName;
}
}
Here i am creating a xml using linq and not getting in the required format.Here is my code
List<string> listvalue = new List<string>();
listvalue.Add("http://example.com/sample.html");
listvalue.Add("http://example.com/new.html");
foreach (string url in listvalue)
{
var document = new HtmlWeb().Load(url);
var urls = document.DocumentNode.Descendants("img")
.Select(e => e.GetAttributeValue("src", null))
.Where(s => !String.IsNullOrEmpty(s));
List<string> asList = urls.ToList();
GenerateXml(url, asList);
}
and
protected void GenerateXml(string url, List<string> listitems) //generateXml
{
XNamespace nsSitemap = "http://www.sitemaps.org/schemas/sitemap/0.9";
XNamespace nsImage = "http://www.google.com/schemas/sitemap-image/1.1";
var sitemap = new XDocument(new XDeclaration("1.0", "UTF-8", ""));
var urlSet = new XElement(nsSitemap + "urlset",
new XAttribute("xmlns", nsSitemap),
new XAttribute(XNamespace.Xmlns + "image", nsImage),
new XElement(nsSitemap + "url",
new XElement(nsSitemap + "loc", url),
from urlNode in listitems
select new XElement(nsImage + "image",
new XElement(nsImage + "loc", urlNode)
)));
sitemap.Add(urlSet);
sitemap.Save(System.Web.HttpContext.Current.Server.MapPath("/Static/sitemaps/Sitemap-image.xml"));
}
I need it in the below format
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
<url>
<loc>http://example.com/sample.html</loc>
<image:image>
<image:loc>http://example.com/image.jpg</image:loc>
</image:image>
<image:image>
<image:loc>http://example.com/photo.jpg</image:loc>
</image:image>
</url>
<url>
<loc>http://example.com/new.html</loc>
<image:image>
<image:loc>http://example.com/newimage.jpg</image:loc>
</image:image>
<image:image>
<image:loc>http://example.com/newphoto.jpg</image:loc>
</image:image>
</url>
</urlset>
But here i am getting a single url tag. How to achieve this? Any suggestion?
It sounds like this is really just a case of wanting to fetch all the URLs (from all the source documents) before you call GenerateXml at all - and remember where each one came from. That's as simple as:
var sources = new List<string>
{
"http://example.com/sample.html",
"http://example.com/new.html"
};
var imagesBySource = sources
.ToDictionary(source => source,
source => new HtmlWeb().Load(url)
.DocumentNode.Descendants("img")
.Select(e => e.GetAttributeValue("src", null))
.Where(s => !String.IsNullOrEmpty(s))
.ToList());
GenerateXml(imagesBySource);
You'd then need to change GenerateXml to take a Dictionary<string, List<string>>. Something like (untested):
protected void GenerateXml(Dictionary<string, List<string>> imagesByUrl)
{
XNamespace nsSitemap = "http://www.sitemaps.org/schemas/sitemap/0.9";
XNamespace nsImage = "http://www.google.com/schemas/sitemap-image/1.1";
var sitemap = new XDocument(new XDeclaration("1.0", "UTF-8", ""));
var urlSet = new XElement(nsSitemap + "urlset",
new XAttribute("xmlns", nsSitemap),
new XAttribute(XNamespace.Xmlns + "image", nsImage),
imagesByUrl.Select(entry =>
new XElement(nsSitemap + "url",
new XElement(nsSitemap + "loc", entry.Key),
from urlNode in entry.Value
select new XElement(nsImage + "image",
new XElement(nsImage + "loc", urlNode)
)
)
);
sitemap.Add(urlSet);
var path = HttpContext.Current.Server.MapPath("/Static/sitemaps/Sitemap-image.xml");
sitemap.Save(path);
}
Note that this won't guarantee that the order of the sources is preserved. If you need that, you should probably create a class with Url and Images properties, and pass a list of those to GenerateXml instead.
My program takes user input and uses it to create a query. The results of that query will then be put into an XML file with XElements based on their selections. I have a string staff which i set equal to the value of staffType.
Where staff is declared w/ snippet of query code:
using (
var conn = new SqlConnection("Server=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;Database=KUDERDEV;User ID=xxxxxxxxxxxxxxxxxx;Password= xxxxxxxx;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;")
)
{
conn.Open();
bool quit = false;
string choice;
string staff;
SqlCommand cmd = new SqlCommand();
while (!quit)
{
Console.WriteLine("Sort by staffType: K12Staff, psStaff, WFStaff or none?");
string staffType = Console.ReadLine();
staff = staffType;
if (staffType == "K12Staff")
{
Console.WriteLine("Sort by code, date, both, or none?");
choice = Console.ReadLine();
switch (choice)
{
case "code":
Console.WriteLine("Sort by code1 or code2?");
string codeCol = Console.ReadLine();
Console.WriteLine("Enter desired code");
string code = Console.ReadLine();
cmd = new SqlCommand("SELECT * FROM Staff WHERE (Staff." + #codeCol + "='" + #code + "') AND staffType ='" + #staffType + "' FOR XML PATH('staff'), ROOT('k12Staff')", conn);
quit = true;
staff = staffType;
break;
When the query string is complete, I go into another using statement without closing the first one to write the XML file. Here I want to change the format of the XML (XElement) depending on which staffType was chosen.
Writing the XML file snippet:
using (cmd)
{
using (var reader = cmd.ExecuteXmlReader())
{
var doc = XDocument.Load(reader);
string path = #"Staff." + DateTime.Now.ToString("yyyyMMdd") + ".xml";
using (var writer = new StreamWriter(path))
{
//if (staff == "k12Staff")
XNamespace ns = "http://specification.sifassociation.org/Implementation/na/3.2/html/CEDS/K12/K12_k12Staff.html";
var root = new XElement(ns + "k12Staff");
foreach (var d in doc.Descendants("staff"))
{
root.Add(new XElement(ns + "staff",
new XElement(ns + "identity",
new XElement(ns + "name",
new XElement(ns + "firstName", first),
new XElement(ns + "lastName", last)
)
),
new XElement(ns + "employment",
new XElement(ns + "positionTitle", position)
),
new XElement(ns + "assignment",
new XElement(ns + "leaID", leaID),
new XElement(ns + "schoolID", schoolID)
),
new XElement(ns + "contact",
new XElement(ns + "phoneNumberList",
new XElement(ns + "number", phone),
new XElement(ns + "phoneNumberIndicator", indicator)
),
new XElement(ns + "emailList",
new XElement(ns + "email", email)
)
),
new XElement(ns + "delete", delete)
Then if the staffType was something different such as "psStaff" then I would change the format of the XML (XElement) to have different names, positions, etc.
So it would be like:
if(staff == "k12Staff"){
format xml here...
}
else if (staff == "psStaff"){
format xml here....
}
etc etc..
My Problem:
In the previous example, my code has if(staff == "k12Staff") but I am told that it is an assigned local variable. I have tried declaring staff outside of the using statements as well as trying to use staff in a using statement like so using(staff) which is how I used my cmd variable. How come my program recognizes cmd but not staff?
You did not post the entire code, so it is not possble to say, where your variable staff should get a value and why it doesn't.
Not assigned means: existing but never got a value...
Try the following: At the place, where you declare your variable change this:
string staff="defaultValue";
On the place where you handle the variable's content change this:
if(staff == "k12Staff"){
format xml here...
}
else if (staff == "psStaff"){
format xml here....
}
else if (staff == "defaultValue"){
//What ever is to be done if all attempts to set "staff" did not work
//You must set a stop mark before your `while (!quit)` and step through.
//There is at least one situation, where `staff` is not set to any value...
//If there's a bug you must fix this, if this is allowed to happen, solve it here...
}