I'm writing to an XML file from which I'm going to retrieve data later.
Here's how I'm writing to the file.
XNamespace testNM = "urn:lst-emp:emp";
XDocument xDoc;
string path = "project_data.xml";
if (!File.Exists(path))
{
xDoc = new XDocument(
new XDeclaration("1.0", "UTF-16", null),
new XElement(testNM + "Test")
);
}
else
{
xDoc = XDocument.Load(path);
}
var element = new XElement("key",
new XAttribute("name", key),
new XElement("Type", type),
new XElement("Value", value));
xDoc.Element(testNM + "Test").Add(element);
// Save to Disk
xDoc.Save(path);
And this is what my XML file looks like after data is written to it.
<?xml version="1.0" encoding="utf-16"?>
<Test xmlns="urn:lst-emp:emp">
<key name="key2" xmlns="">
<Type>int</Type>
<Value>12312</Value>
</key>
<key name="key3" xmlns="">
<Type>String</Type>
<Value>asdfasd</Value>
</key>
</Test>
Now what would be the simplest way to get the name attribute value (key2 and key3 in this case) along with the Type and Value attribute values.
Load the document;
XDocument doc = XDocument.Load(#"doc.xml");
Loop the key nodes reading what you need;
foreach (var keyNode in doc.Root.Elements("key"))
{
var name = keyNode.Attribute("name");
var type = (string)keyNode.Element("Type"); // or .value to throw if there is no node
...
}
Related
Below is my controller Code which generate the XML file and save this file and specific location
List<propertyfile> data = ws.GetPropertyFiles();
XmlDocument writer = new XmlDocument();
// Create XML declaration
XmlNode declaration = writer.CreateNode(XmlNodeType.XmlDeclaration, null, null);
writer.AppendChild(declaration);
// Make the root element first
XmlElement root = writer.CreateElement("Channel");
writer.AppendChild(root);
//XmlElement rot = writer.CreateElement("item");
//writer.AppendChild(rot);
//Server.MapPath //HttpContext.Current.Server.MapPath("~")
string wallFolderPath = Server.MapPath("~/assets/wall/");
var newGuid = Guid.NewGuid().ToString();
string filename = wallFolderPath+ "wallview_" +newGuid+".xml";
var pathlocal = ServerUrlPath+"assets/wall/" + "wallview_" + newGuid + ".xml";
ViewBag.wallpath = pathlocal;
System.IO.File.Create(filename).Dispose();
foreach (var a in data)
{
if (a.Path != null && a.ThumbnailPath != null)
{
XmlElement id = writer.CreateElement("item");
XmlElement name = writer.CreateElement("title");
name.InnerText = a.Name;
XmlElement age = writer.CreateElement("media:description");
var e_path = a.Path;
XmlElement anchor = writer.CreateElement("a");
e_path = e_path.Substring(2, e_path.Length - 2);
e_path= ServerUrlPath + e_path;
anchor.SetAttribute("href", e_path);
age.AppendChild(anchor);
//age.SetAttribute("href", e_path);
XmlElement linq = writer.CreateElement("link");
var e_linq = a.Path;
e_linq = e_linq.Substring(2, e_linq.Length - 2);
linq.InnerText = ServerUrlPath + e_linq;
XmlElement thumb = writer.CreateElement("media:thumbnail");
var e_thumbnail = a.ThumbnailPath;
e_thumbnail = e_thumbnail.Substring(2, e_thumbnail.Length - 2);
e_thumbnail = ServerUrlPath + e_thumbnail;
thumb.SetAttribute("url", e_thumbnail);
XmlElement content = writer.CreateElement("media:content");
content.SetAttribute("url", e_thumbnail);
id.AppendChild(name);
id.AppendChild(age);
id.AppendChild(linq);
id.AppendChild(thumb);
id.AppendChild(content);
root.AppendChild(id);
writer.AppendChild(root);
}
}
writer.Save(filename);
Result(XML File Generated)
<Channel>
<item>
<title>RedbrushAlpha.png</title>
<description>
<a href="http://localhost:2023/Files/aa1989f3-f4bd-489d-abca-b0c7cdfa4ae7.png"/>
</description>
<link>
http://localhost:2023/Files/aa1989f3-f4bd-489d-abca-b0c7cdfa4ae7.png
</link>
<thumbnail url="http://localhost:2023/FilesThumbs/aa1989f3-f4bd-489d-abca-b0c7cdfa4ae7.Jpeg"/>
<content url="http://localhost:2023/FilesThumbs/aa1989f3-f4bd-489d-abca-b0c7cdfa4ae7.Jpeg"/>
</item>
But I Need file generate similar to this with rss tag and tag like Below is the xml file code and i need to create file similar to this
<?xml version="1.0" ?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<item>
<title>mastercard.png</title>
<media:description><a href=' http://localhost:2023/Files/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.png'</media:description>
<link>http://localhost:2023/Files/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.png</link>
<media:thumbnail url="http://localhost:2023/FilesThumbs/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.Jpeg" />
<media:content url="http://localhost:2023/FilesThumbs/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.Jpeg" />
</item>
</channel>
</rss>
hi please check updated code with some changes you will now get expect output
you just need to update value of tag and your output will be ready
XmlDocument writer = new XmlDocument();
// Create XML declaration
XmlNode declaration = writer.CreateNode(XmlNodeType.XmlDeclaration, null, null);
writer.AppendChild(declaration);
//add rss node over here
XmlElement rssElement = writer.CreateElement("rss");
rssElement.SetAttribute("version", "2.0");
rssElement.SetAttribute("xmlns:media", "http://search.yahoo.com/mrss/");
rssElement.SetAttribute("xmlns:atom", "http://www.w3.org/2005/Atom");
//Channel
XmlElement channelElement = writer.CreateElement("Channel");
XmlElement itemElement = writer.CreateElement("item");
//title
XmlElement titleElement = writer.CreateElement("title");
titleElement.InnerText = "mastercard.png";
itemElement.AppendChild(titleElement);
//media:description
XmlElement media_DescriptionElement = writer.CreateElement("media", "description", "media:description");
media_DescriptionElement.InnerText = "<a href=' http://localhost:2023/Files/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.png";
itemElement.AppendChild(media_DescriptionElement);
//link
XmlElement linkElement = writer.CreateElement("link");
linkElement.InnerText = "http://localhost:2023/Files/aa1989f3-f4bd-489d-abca-b0c7cdfa4ae7.png";
itemElement.AppendChild(linkElement);
//media:thumbnail
XmlElement media_ThumbnailElement = writer.CreateElement("media", "thumbnail", "media:thumbnail");
media_ThumbnailElement.SetAttribute("url", "http://localhost:2023/FilesThumbs/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.Jpeg");
itemElement.AppendChild(media_ThumbnailElement);
//media:content
XmlElement media_ContentElement = writer.CreateElement("media", "content", "media:content");
media_ContentElement.SetAttribute("url", "http://localhost:2023/FilesThumbs/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.Jpeg");
itemElement.AppendChild(media_ContentElement);
channelElement.AppendChild(itemElement);
rssElement.AppendChild(channelElement);
writer.AppendChild(rssElement);
Output
<?xml version="1.0"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom">
<Channel>
<item>
<title>mastercard.png</title>
<media:description xmlns:media="media:description"><a href=' http://localhost:2023/Files/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.png</media:description>
<link>http://localhost:2023/Files/aa1989f3-f4bd-489d-abca-b0c7cdfa4ae7.png</link>
<media:thumbnail url="http://localhost:2023/FilesThumbs/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.Jpeg" xmlns:media="media:thumbnail" />
<media:content url="http://localhost:2023/FilesThumbs/054ee47b-7ecf-42d1-bfcc-06ac5f84b6d4.Jpeg" xmlns:media="media:content" />
</item>
</Channel>
</rss>
Well, first and foremost, although it doesn't really change anything, it's important to realize that both XDocument and XElement accepts params, i.e. a list of items to add. This will make your code much more readable. For example:
var xdoc = new XDocument(
new XElement("root",
new XElement("foo"),
new XElement("bar")
);
);
That way the hierarchy is very clear, and you're not throwing variables all over the place.
Second, you literally made your root <channel>, rather than <rss>, so simply make <rss> your root element in your XDocument and then add <channel> to that, rather than directly to the XDocument as you're doing now.
Third, you can add attributes to elements using XAttribute. However, for namespaces, you want to persist these in a variable, so you can utilize them later as you're building your XML document. For example:
var media = XNamespace.Get("http://search.yahoo.com/mrss/");
var atom = XNamespace.Get("http://www.w3.org/2005/Atom");
var xdoc = new XDocument(
new XElement("rss",
new XAttribute("version", "2.0"),
new XAttribute(XNamespace.Xmlns + "media", media),
new XAttribute(XNamespace.Xmlns + "atom", atom),
new XElement("channel",
...
)
)
);
Then, when you need to use one of these namespaces, you concatentate it to the element name. For example, with media:thumbnail:
new XElement(media + "thumbnail",
new XAttribute("url", e_thumbnail)
)
Finally, if you use ToString on the XDocument, it will strip the XML declaration, for some boneheaded reason. Instead, you need to use a TextWriter to get the output:
var sb = new StringBuilder();
using (TextWriter writer = new Utf8StringWriter(sb))
{
xdoc.Save(writer);
}
var xmlString = sb.ToString();
FWIW, this is why you should name your XDocument variable something like xdoc rather than writer. For one, XDocument doesn't actually "write" anything, but also, writer is generally reserved for actual "writers" like TextWriter. That's all semantic, of course, but especially when dealing with XML, which usually involves voluminous amounts of code, you want it to be as readable and understandable as possible.
One last little tip. When building XML in the way I've shown here, you can pass actual enumerables just as well as single items. For example, let's say you created your list of channel items separately, such that you have a List<XElement> called items. You can actually just do:
new XElement("channel",
new XElement("title", "My Awesome Channel"),
new XElement("link", "https://foo.com/rss"),
new XElement("description", "Best channel ever!"),
items
)
EDIT
I completely forgot about Utf8StringWriter. That's a derived class of StringWriter, because StringWriter stupidly returns UTF16, and there's no way to modify that without deriving from it. The implementation is simple, but you'll need to add this to your project:
internal sealed class Utf8StringWriter : StringWriter
{
public Utf8StringWriter(StringBuilder sb)
: base(sb)
{
}
public override Encoding Encoding
{
get { return Encoding.UTF8; }
}
}
If you want to put this in a class library or something and share it between projects, just change internal to public.
I'm using the following code to write an XML file to disk. If I change the values for each field and re-run the code, the values saved will simply be replaced.
I've looked around here but I see no way to automatically append the new values to the end of the file as a new element and not simply replace everything.
XNamespace empNM = "urn:lst-emp:emp";
XDocument xDoc = new XDocument(
new XDeclaration("1.0", "UTF-16", null),
new XElement(empNM + "Employees",
new XElement("Employee",
new XComment("Only 3 elements for demo purposes"),
new XElement("EmpId", "5"),
new XElement("Name", "Kimmy"),
new XElement("Sex", "Female")
)));
StringWriter sw = new StringWriter();
XmlWriter xWrite = XmlWriter.Create(sw);
xDoc.Save(xWrite);
xWrite.Close();
// Save to Disk
xDoc.Save("C:\\tempFolder\\test.xml");
Console.WriteLine("Saved");
Also, could someone please explain what "urn:lst-emp:emp"; in the first line does.
void Main()
{
XNamespace empNM = "urn:lst-emp:emp";
XDocument xDoc ;
string path="C:\\tempFolder\\test.xml";
if(!File.Exists(path))
{
xDoc = new XDocument(
new XDeclaration("1.0", "UTF-16", null),
new XElement(empNM + "Employees")
);
}
else
{
xDoc=XDocument.Load(path);
}
var element=new XElement("Employee",
new XComment("Only 3 elements for demo purposes"),
new XElement("EmpId", "5"),
new XElement("Name", "Kimmy"),
new XElement("Sex", "Female"));
xDoc.Element(empNM+"Employees").Add(element);
// Save to Disk
xDoc.Save(path);
Console.WriteLine("Saved");
}
Here is the Xml generated:
<?xml version="1.0" encoding="utf-16"?>
<Employees xmlns="urn:lst-emp:emp">
<Employee xmlns="">
<!--Only 3 elements for demo purposes-->
<EmpId>5</EmpId>
<Name>Kimmy</Name>
<Sex>Female</Sex>
</Employee>
<Employee xmlns="">
<!--Only 3 elements for demo purposes-->
<EmpId>5</EmpId>
<Name>Kimmy</Name>
<Sex>Female</Sex>
</Employee>
</Employees>
Building an XML XDocument to push to web service and the root element needs namespace values this is what the XML form should look like....
<shipment-feed xmlns="http://seller.marketplace.sears.com/oms/v5"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://seller.marketplace.sears.com/oms/v5 asn.xsd ">
<shipment>
<header>
<asn-number>00601780002</asn-number>
<po-number>0060180</po-number>
<po-date>2009-09-26</po-date>
</header>
<detail>
<tracking-number>UPS1XXX</tracking-number>
<ship-date>2001-01-01</ship-date>
<shipping-carrier>UPS</shipping-carrier>
<shipping-method>GROUND</shipping-method>
<package-detail>
<line-number>1</line-number>
<item-id>AB12345678912345456789123456789CD</item-id>
<quantity>1</quantity>
</package-detail>
</detail>
</shipment>
</shipment-feed>
This is the xml that I'm getting....
<?xml version="1.0" encoding="utf-8"?>
<shipment-feed xmlns="http://seller.marketplace.sears.com/oms/v5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsischemalocation="http://seller.marketplace.sears.com/oms/v5 asn.xsd">
<shipment xmlns="">
<header>
<asn-number>2824565201311</asn-number>
<po-number>2824565</po-number>
<po-date>2013-11-14</po-date>
</header>
<details>
<tracking-number>579040914892</tracking-number>
<ship-date>2013-11-14</ship-date>
<shipping-carrier>FEDEX</shipping-carrier>
<shipping-method>Ground</shipping-method>
<package-details>
<line-number>1</line-number>
<item-id>LTH7XB1MW-EA</item-id>
<quantity>3</quantity>
</package-details>
</details>
</shipment>
<shipment xmlns="">
<header>
<asn-number>2821596201311</asn-number>
<po-number>2821596</po-number>
<po-date>2013-11-13</po-date>
</header>
<details>
<tracking-number>9405515901119923380663</tracking-number>
<ship-date>2013-11-14</ship-date>
<shipping-carrier>USPS</shipping-carrier>
<shipping-method>Priority Mail</shipping-method>
<package-details>
<line-number>1</line-number>
<item-id>CWD93151-EA</item-id>
<quantity>6</quantity>
</package-details>
<package-details>
<line-number>2</line-number>
<item-id>CWD93901-EA</item-id>
<quantity>4</quantity>
</package-details>
</details>
</shipment>
</shipment-feed>
This is the C# code I created....
XNamespace ns1 = "http://seller.marketplace.sears.com/oms/v5";
XNamespace ns2 = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace ns3 = "http://seller.marketplace.sears.com/oms/v5 asn.xsd";
XDocument doc = new XDocument();
XElement root = new XElement(ns1 + "shipment-feed",
new XAttribute("xmlns" , "http://seller.marketplace.sears.com/oms/v5"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
new XAttribute("xsi" + "schemalocation", "http://seller.marketplace.sears.com/oms/v5 asn.xsd"));
doc.Add(root);
int x = 1;
foreach (SearsOrder s in SearsList)
{
XElement shipment = new XElement("shipment",
new XElement("header",
new XElement("asn-number", s.asnnumber),
new XElement("po-number", s.ponumber),
new XElement("po-date", s.podate)),
new XElement("details",
new XElement("tracking-number", s.trackingnum),
new XElement("ship-date", s.shipdate),
new XElement("shipping-carrier", s.carrier),
new XElement("shipping-method", s.method),
s.orderitems.Select(i => new XElement("package-details",
new XElement("line-number", x++),
new XElement("item-id", i.itemid),
new XElement("quantity", i.quantity)))
));
doc.Root.Add(shipment);
x = 1;
}
The fist problem is the first child node I'm not seeing where that is coming from because that node is not even declared until the foreach loop. I was under the impression that I was only adding attributes to the root element.
and the other problem is removing the xml declaration
This sort of the thing is the problem:
new XElement("shipment", ...)
You want the shipment elements to be in the "http://seller.marketplace.sears.com/oms/v5" namespace - so you need to make that explicit. That won't show up in the resulting XML directly, because they'll inherit that as the default namespace specified in the root. Basically, wherever you're creating an element, you probably want to use ns1. So:
new XElement(ns1 + "shipment", new XElement(ns1 + "header", ...), ...)
To understand more about why this is required, you should read up on namespace defaulting in the XML Namespaces specification.
and the other problem is removing the xml declaration
So add an XDeclaration to the XDocument:
XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"))
I am trying to find a node in my xml file but getting the error ( see title)?
// instantiate XmlDocument and load XML from file
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\temp\test2.xml");
var node = doc.SelectSingleNode("/Offers/Offer/ID=[text()='1']");
var test = node;
xml
<?xml version="1.0" encoding="utf-8"?>
<Offers>
<Offer>
<Model>AAAA</Model>
<ID>1</ID>
<Name>First offer</Name>
</Offer>
<Offer>
<Model>BBBB</Model>
<ID>2</ID>
<Name>Second offer</Name>
</Offer>
</Offers>
Remove the = after ID:
var node = doc.SelectSingleNode("/Offers/Offer/ID=[text()='1']");
becomes:
var node = doc.SelectSingleNode("/Offers/Offer/ID[text()='1']");
I would like to filter with high performance XML elements from an XML document.
Take for instance this XML file with contacts:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="asistentes.xslt"?>
<contactlist evento="Cena Navidad 2010" empresa="company">
<contact type="1" id="1">
<name>Name1</name>
<email>xxxx#zzzz.es</email>
<confirmado>SI</confirmado>
</contact>
<contact type="1" id="2">
<name>Name2</name>
<email>xxxxxxxxx#zzzze.es</email>
<confirmado>Sin confirmar</confirmado>
</contact>
</contaclist>
My current code to filter from this XML document:
using System;
using System.Xml.Linq;
class Test
{
static void Main()
{
string xml = #" the xml above";
XDocument doc = XDocument.Parse(xml);
foreach (XElement element in doc.Descendants("contact")) {
Console.WriteLine(element);
var id = element.Attribute("id").Value;
var valor = element.Descendants("confirmado").ToList()[0].Value;
var email = element.Descendants("email").ToList()[0].Value;
var name = element.Descendants("name").ToList()[0].Value;
if (valor.ToString() == "SI") { }
}
}
}
What would be the best way to optimize this code to filter on <confirmado> element content?
var doc = XDocument.Parse(xml);
var query = from contact in doc.Root.Elements("contact")
let confirmado = (string)contact.Element("confirmado")
where confirmado == "SI"
select new
{
Id = (int)contact.Attribute("id"),
Name = (string)contact.Element("name"),
Email = (string)contact.Element("email"),
Valor = confirmado
};
foreach (var contact in query)
{
...
}
Points of interest:
doc.Root.Elements("contact") selects only the <contact> elements in the document root, instead of searching the whole document for <contact> elements.
The XElement.Element method returns the first child element with the given name. No need to convert the child elements to a list and take the first element.
The XElement and XAttribute classes provide a wide selection of convenient conversion operators.
You could use LINQ:
foreach (XElement element in doc.Descendants("contact").Where(c => c.Element("confirmado").Value == "SI"))