How to generate xml and format it from object in c#? - c#

Here I am trying to format XML from a list and I am not getting the proper format. Here is my code:
protected void GenerateXml(string url, List<string> listitems) //generateXml
{
XNamespace nsXhtml = "http://www.w3.org/1999/xhtml";
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", nsXhtml),
from urlNode in listitems
select
new XElement(
nsSitemap + "url",
new XElement(nsSitemap + "loc", url),
new XElement(nsSitemap + "image",
new XElement(nsSitemap + "imageloc", urlNode))));
sitemap.Add(urlSet);
sitemap.Save(System.Web.HttpContext.Current.Server.MapPath("/Static/sitemaps/Sitemap-image.xml"));
}
... and getting the format like this:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.w3.org/1999/xhtml">
<url>
<loc>http://example.com/intl/cars/new-models/the-new-s90</loc>
<image>
<imageloc>http://example.com/static/images/volvo-logo-scaled.png</imageloc>
</image>
</url>
<url>
<loc>http://example.com/intl/cars/new-models/the-new-s90</loc>
<image>
<imageloc>http://assets.example.com/intl/~/media/images/galleries/new-cars/packshots/small/allnew_xc90-side_2.png</imageloc>
</image>
</url>
</urlset>
But I need in this 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>
</urlset>
Any suggestion?

In addition to properly handling the multiple nested elements, you never assigned the image prefix to the elements that are supposed to have them, you continue to use the global namespace:
new XElement(nsSitemap + "image",
new XElement(nsSitemap + "imageloc", urlNode)
nsSitemap should be nsImage, and "imageloc" should be "loc".
A couple minor tweaks to your code will get you what you're looking for:
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"));
}
Notice the following changes:
new XAttribute(XNamespace.Xmlns + "image", nsImage);
This sets the namespace correctly to mach your expected output.
new XElement(nsImage + "image",
new XElement(nsImage + "loc", urlNode)
This sets the image prefix correctly.
Notice how "loc" and "url" were moved to before the from query.
The above code results in the following output XML:
<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>
</urlset>

Related

How to format xml using linq?

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.

C# with XDocument and xsi:schemaLocation

I want to create the following XML.
<?xml version="1.0" encoding="utf-8"?>
<MyNode xsi:schemaLocation="https://MyScheme.com/v1-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://MyScheme.com/v1-0 Sscheme.xsd">
<MyInfo>
<MyNumber>string1</MyNumber>
<MyName>string2</MyName>
<MyAddress>string3</MyAddress>
</MyInfo>
<MyInfo2>
<FirstName>string4</FirstName>
</MyInfo2>
</MyNode>
I'm using this code.
XNamespace xmlns = "https://MyScheme.com/v1-0 Sscheme.xsd";
XNamespace xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance");
XNamespace schemaLocation = XNamespace.Get("https://MyScheme.com/v1-0");
XDocument xmlDocument = new XDocument(
new XElement(xmlns + "MyNode",
new XAttribute(xsi + "schemaLocation", schemaLocation),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XElement("MyInfo",
new XElement("MyNumber", "string1"),
new XElement("MyName", "string2"),
new XElement("MyAddress", "string3")
),
new XElement("MyInfo2",
new XElement("FirstName", "string4")
)
)
);
xmlDocument.Save("C:\\MyXml.xml");
However, I'm getting xmlns="" inside tags MyInfo and MyInfo2.
Can somebody help me to create the correct XML?
You need to use xmlns XNamespace for all elements, because that is default namespace and it is declared at root level element. Note that descendant elements inherit ancestor default namespace implicitly, unless otherwise specified :
XDocument xmlDocument = new XDocument(
new XElement(xmlns + "MyNode",
new XAttribute(xsi + "schemaLocation", schemaLocation),
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XElement(xmlns+"MyInfo",
new XElement(xmlns+"MyNumber", "string1"),
new XElement(xmlns+"MyName", "string2"),
new XElement(xmlns+"MyAddress", "string3")
),
new XElement(xmlns+"MyInfo2",
new XElement(xmlns+"FirstName", "string4")
)
)
);
Dotnetfiddle Demo

C# XML - Why does this Code keep failing with 0x3A Error?

i have following code example:
PlentySoapRequest_GetAuthentificationToken username = new PlentySoapRequest_GetAuthentificationToken();
username.Username = user_textbox.ToString();
username.Userpass = password_textbox.ToString();
Uri uri = new Uri("http://www.****.de/plenty/api/soap/version105/");
XNamespace soapenv = #"http://schemas.xmlsoap.org/soap/envelope/";
XNamespace xsi = #"http://www.w3.org/2001/XMLSchema-instance";
XNamespace xsd = #"http://www.w3.org/2001/XMLSchema";
XNamespace ver = #"http://www.****.de/plenty/api/soap/version105/";
var document = new XDocument(
new XDeclaration("1.0", "utf-8", String.Empty),
new XElement(soapenv + "Envelope",
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XAttribute(XNamespace.Xmlns + "xsd" , xsd),
new XAttribute(XNamespace.Xmlns + "soapenv" , soapenv),
new XAttribute(XNamespace.Xmlns + "ver" , ver),
new XElement(soapenv + "Header"),
new XElement(soapenv + "Body",
new XElement(ver + "GetAuthentificationToken",
new XElement("oLogin" + xsi + "type" + ver + "PlentySoapRequest_GetAuthentificationToken",
new XAttribute("Username" + xsi + "type" + xsd + "string", username.Username),
new XAttribute("Userpass" + xsi + "type" + xsd + "string", username.Userpass)
)
)
)
)
);
I keep getting the error message in the first line. "plentysoaprequest...."
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
if I comment out those lines, it keeps say it is in the first line of the code.
Edit:
the xml should look like this:
<soapenv:Body>
<ver:GetAuthentificationToken>
<oLogin xsi:type="ver:PlentySoapRequest_GetAuthentificationToken">
<!--You may enter the following 2 items in any order-->
<Username xsi:type="xsd:string">apitest</Username>
<Userpass xsi:type="xsd:string">apitest</Userpass>
</oLogin>
</ver:GetAuthentificationToken>
so there seems to be a problem with the xml-sysntax.
I cant figure out how to set xsi:type or xsi:type
"oLogin" + xsi + "type" will create a string with value "oLoginhttp://www.w3.org/2001/XMLSchema-instancetype". That's not a valid name...
You need something a little closer to this:
var document = new XDocument(
new XDeclaration("1.0", "utf-8", String.Empty),
new XElement(soapenv + "Envelope",
new XAttribute(XNamespace.Xmlns + "xsi", xsi),
new XAttribute(XNamespace.Xmlns + "xsd", xsd),
new XAttribute(XNamespace.Xmlns + "soapenv", soapenv),
new XAttribute(XNamespace.Xmlns + "ver", ver),
new XElement(soapenv + "Header"),
new XElement(soapenv + "Body",
new XElement(ver + "GetAuthentificationToken",
new XElement(xsi + "Login",
new XAttribute(xsi + "type", "blahblah"),
new XElement("Username",
new XAttribute(xsi + "type", "xsd:string"),
"myUserName")
)
)
)
)
);
Which generates this XML
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ver="http://www.****.de/plenty/api/soap/version105/">
<soapenv:Header />
<soapenv:Body>
<ver:GetAuthentificationToken>
<xsi:Login xsi:type="blahblah">
<Username xsi:type="xsd:string">myUserName</Username>
</xsi:Login>
</ver:GetAuthentificationToken>
</soapenv:Body>
</soapenv:Envelope>

How to create an Xml with multiple namescapes using XDocument

I would like to create a document with multiple namespaces (see Xml below). How can I do that using XDocument? My final result should the following:
<?xml version="1.0" encoding="utf-8"?>
<a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns:os="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://schemas.zune.net/catalog/apps/2008/02">
<a:link rel="prev" type="application/atom+xml" href="myUrl" />
<a:link rel="next" type="application/atom+xml" href="myUrl" />
<a:link rel="self" type="application/atom+xml" href="myUrl" />
<a:updated>2008-05-20T22:50:46.7932864Z</a:updated>
Here is the code I have so far.
XNamespace nsW3Atom = "http://www.w3.org/2005/Atom";
XNamespace nsOs = "http://a9.com/-/spec/opensearch/1.1/";
XNamespace nsZune = "http://schemas.zune.net/calatog/apps/2008/02";
XDocument doc =
new XDocument(
// new XDeclaration("1.0", "utf-8", "no"),
new XElement("feed",
new XAttribute("a", nsW3Atom),
new XAttribute("os", nsOs),
new XAttribute("os2", nsZune),
new XElement(XNamespace.Xmlns + "link", new XAttribute("rel", "prev"), new XAttribute("type", "application/atom+xml")),
new XElement(XNamespace.Xmlns + "link", new XAttribute("rel", "next"), new XAttribute("type", "application/atom+xml")),
new XElement(XNamespace.Xmlns + "link", new XAttribute("rel", "self"), new XAttribute("type", "application/atom+xml"))));
Thank you in advance for the help!
XNamespace a="http://www.w3.org/2005/Atom";
XNamespace os = "http://a9.com/-/spec/opensearch/1.1/";
XNamespace def = "http://schemas.zune.net/catalog/apps/2008/02";
var doc =
new XDocument(new XElement(a + "feed",
new XAttribute(XNamespace.Xmlns + "a", a),
new XAttribute(XNamespace.Xmlns + "os", os),
new XAttribute("xmlns", def)));
then if You want to use the a Namespace, prefix any element with a+
When creating the attributes use the xmlns: prefix.
new XAttribute("xmlns:a", nsW3Atom),
new XAttribute("xmlns:os", nsOs),
new XAttribute("xmlns:os2", nsZune)

How to generate xsi:schemalocation attribute correctly when generating a dynamic sitemap.xml with LINQ to XML?

I am generating a dynamic sitemap.xml
According to sitemaps.org this is the header for a sitemap.xml
<?xml version='1.0' encoding='UTF-8'?>
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
...
</url>
</urlset>
So I'm using LINQ To XML to generate the sitemap.xml
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
return new XElement(ns + "urlset",
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
//new XAttribute("xsi:schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"),
from node in new GetNodes()
select new XElement(ns + "url",
new XElement(ns + "loc", node.Loc),
new XElement(ns + "lastmod", node.LastMod),
new XElement(ns + "priority", node.Priority)
)
).ToString();
The commented line is the one i cannot get right.
How can i set the "xsi:schemalocation" attribute?
Thanks.
Ok, I got it right. Thanks to Mike Caron
If I declare the XAtrribute(XNamespace.Xmlns + "xsi",...) then it works
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
return new XElement(ns + "urlset",
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
new XAttribute(xsi + "schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"),
from node in GetNodes()
select new XElement(ns + "url",
new XElement(ns + "loc", node.Loc),
new XElement(ns + "lastmod", node.LastMod),
new XElement(ns + "priority", node.Priority)
)
).ToString();
I don't know LINQ to XML, but after a quick peek at the documentation, try this:
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
return new XElement(ns + "urlset",
new XAttribute(xsi + "schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"),
from node in new GetNodes()
select new XElement(ns + "url",
new XElement(ns + "loc", node.Loc),
new XElement(ns + "lastmod", node.LastMod),
new XElement(ns + "priority", node.Priority)
)
).ToString();
Note that I'm not setting the xmlns attributes explicitly. I suspect they're generated automatically. Also, caveat emptor, since this is not tested.

Categories