Update XML file with C# - c#

I have a xml file:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration xmlns="http://test.org/SDK/Configuration.xsd">
<ApplicationName>
<ApplicationUri>123</ApplicationUri>
<ApplicationUri>456</ApplicationUri>
</ApplicationName>
</ApplicationConfiguration>
What I want is set the value of ApplicationUri from 456 to 789 in C# code.
I wrote this code:
string docaddress = "testfile.xml";
XDocument doc = XDocument.Load(docaddress);
doc.Element("ApplicationConfiguration")
.Elements("ApplicationName").FirstOrDefault()
.SetElementValue("ApplicationUri", "789");
doc.Save(docaddress);
The problems are:
There is no error while running. I think the element ApplicationConfiguration is not correct. But when I delete the line xmlns=... from the xml file, it runs normally
The value 789 is replaced with 123, but not 456 as I want (same element name)
Can you tell me how to fix those problems?

Hello and welcome to Stack Overflow!
The xmlns attribute on the ApplicationConfiguration element makes that the root.
So you get the root first. Then you replace the values of each descendant, selecting locally by name with the element name you want. something like this:
string docaddress = "C:\\temp\\testfile.xml";
XDocument doc = XDocument.Load(docaddress);
var root = doc.Root;
var descendants = root.Descendants();
var these = root.Descendants().Where(p => p.Name.LocalName == "ApplicationUri");
foreach (var elem in these)
{
elem.Value = "789";
}
doc.Save(docaddress);

I added namespace to your code :
string docaddress = "testfile.xml";
XDocument doc = XDocument.Load(docaddress);
XNamespace ns = doc.Root.GetDefaultNamespace();
doc.Element(ns + "ApplicationConfiguration")
.Elements(ns + "ApplicationName").FirstOrDefault()
.SetElementValue(ns + "ApplicationUri", "789");
doc.Save(docaddress);

IMHO, here is an easiest method.
It is taking care of the XML default namespace.
No loops. Set based approach.
c#
void Main()
{
const string fileName = #"e:\temp\hala.xml";
const string searchFor = "456";
const string replaceWith = "789";
XDocument doc = XDocument.Load(fileName);
XNamespace ns = doc.Root.GetDefaultNamespace();
// step #1: find element based on the search value
XElement xmlFragment = doc.Descendants(ns + "ApplicationUri")
.Where(d => d.Value.Equals(searchFor)).FirstOrDefault();
// step #2: if found, set its value
if(xmlFragment != null)
xmlFragment.SetValue(replaceWith);
doc.Save(fileName);
}

Related

How to get "Header" node in C#

I'm trying to get the "Header" node from this XML document and to output the XML string to the Textbox in C#, here is the input xml file:
<?xml version="1.0" encoding="UTF-8"?>
<nsSAFT:AuditFile xmlns:nsSAFT="mfp:napz:saa:d1111:declaration:v22">
<nsSAFT:Header>
<nsSAFT:AuditFileVersion>XX</nsSAFT:AuditFileVersion>
<nsSAFT:AuditFileCountry>XX</nsSAFT:AuditFileCountry>
<nsSAFT:AuditFileDateCreated>XXX</nsSAFT:AuditFileDateCreated>
<nsSAFT:SoftwareCompanyName>XXX</nsSAFT:SoftwareCompanyName>
<nsSAFT:SoftwareID>XXXX</nsSAFT:SoftwareID>
<nsSAFT:SoftwareVersion>XXX</nsSAFT:SoftwareVersion>
<nsSAFT:Company>
<nsSAFT:RegistrationNumber>XXX</nsSAFT:RegistrationNumber>
<nsSAFT:Name>XXXX</nsSAFT:Name>
<nsSAFT:Address>
<nsSAFT:StreetName>XXX</nsSAFT:StreetName>
<nsSAFT:City>XXXX</nsSAFT:City>
<nsSAFT:PostalCode>XXX</nsSAFT:PostalCode>
<nsSAFT:Country>XXX</nsSAFT:Country>
</nsSAFT:Address>
<nsSAFT:Contact>
<nsSAFT:ContactPerson>
<nsSAFT:FirstName>XXX</nsSAFT:FirstName>
<nsSAFT:LastName>XXXX</nsSAFT:LastName>
</nsSAFT:ContactPerson>
<nsSAFT:Telephone>XXXXX</nsSAFT:Telephone>
</nsSAFT:Contact>
<nsSAFT:BankAccount>
<nsSAFT:IBANNumber>XXXX</nsSAFT:IBANNumber>
</nsSAFT:BankAccount>
</nsSAFT:Company>
<nsSAFT:DefaultCurrencyCode>XXXX</nsSAFT:DefaultCurrencyCode>
<nsSAFT:SelectionCriteria>
<nsSAFT:SelectionStartDate>XXXX</nsSAFT:SelectionStartDate>
<nsSAFT:SelectionEndDate>XXX</nsSAFT:SelectionEndDate>
</nsSAFT:SelectionCriteria>
<nsSAFT:HeaderComment>X</nsSAFT:HeaderComment>
<nsSAFT:SegmentIndex>X</nsSAFT:SegmentIndex>
<nsSAFT:TotalSegmentsInsequence>X</nsSAFT:TotalSegmentsInsequence>
<nsSAFT:TaxAccountingBasis>XXXX</nsSAFT:TaxAccountingBasis>
</nsSAFT:Header>
</nsSAFT:AuditFile>
Here is how I'm trying to get the "Header" node, with the originalDoc.Element("Header");
XDocument originalDoc = XDocument.Load(fileName);
var list = originalDoc.Element("Header");
string output = list.ToString();
richTextBox1.Text = output;
But in the the debugger, the the list variable is always empty?
The result that I'm expecting:
<nsSAFT:Header>
<nsSAFT:AuditFileVersion>XX</nsSAFT:AuditFileVersion>
<nsSAFT:AuditFileCountry>XX</nsSAFT:AuditFileCountry>
<nsSAFT:AuditFileDateCreated>XXX</nsSAFT:AuditFileDateCreated>
<nsSAFT:SoftwareCompanyName>XXX</nsSAFT:SoftwareCompanyName>
<nsSAFT:SoftwareID>XXXX</nsSAFT:SoftwareID>
<nsSAFT:SoftwareVersion>XXX</nsSAFT:SoftwareVersion>
<nsSAFT:Company>
<nsSAFT:RegistrationNumber>XXX</nsSAFT:RegistrationNumber>
<nsSAFT:Name>XXXX</nsSAFT:Name>
<nsSAFT:Address>
<nsSAFT:StreetName>XXX</nsSAFT:StreetName>
<nsSAFT:City>XXXX</nsSAFT:City>
<nsSAFT:PostalCode>XXX</nsSAFT:PostalCode>
<nsSAFT:Country>XXX</nsSAFT:Country>
</nsSAFT:Address>
<nsSAFT:Contact>
<nsSAFT:ContactPerson>
<nsSAFT:FirstName>XXX</nsSAFT:FirstName>
<nsSAFT:LastName>XXXX</nsSAFT:LastName>
</nsSAFT:ContactPerson>
<nsSAFT:Telephone>XXXXX</nsSAFT:Telephone>
</nsSAFT:Contact>
<nsSAFT:BankAccount>
<nsSAFT:IBANNumber>XXXX</nsSAFT:IBANNumber>
</nsSAFT:BankAccount>
</nsSAFT:Company>
<nsSAFT:DefaultCurrencyCode>XXXX</nsSAFT:DefaultCurrencyCode>
<nsSAFT:SelectionCriteria>
<nsSAFT:SelectionStartDate>XXXX</nsSAFT:SelectionStartDate>
<nsSAFT:SelectionEndDate>XXX</nsSAFT:SelectionEndDate>
</nsSAFT:SelectionCriteria>
<nsSAFT:HeaderComment>X</nsSAFT:HeaderComment>
<nsSAFT:SegmentIndex>X</nsSAFT:SegmentIndex>
<nsSAFT:TotalSegmentsInsequence>X</nsSAFT:TotalSegmentsInsequence>
<nsSAFT:TaxAccountingBasis>XXXX</nsSAFT:TaxAccountingBasis>
</nsSAFT:Header>
Please try the following solution.
As #RobertHarvey pointed out, it was a need to add namespace handling.
c#
void Main()
{
const string inputFile = #"e:\Temp\eXtreme.xml";
XDocument xdoc = XDocument.Load(inputFile);
XNamespace ns = xdoc.Root.GetNamespaceOfPrefix("nsSAFT");
var header = xdoc.Descendants(ns + "Header").FirstOrDefault();
string output = header.ToString();
}

Unknown error? for XDocument.Descendants [duplicate]

I have this xml string:
<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="self" type="application/atom+xml" href="/docs" />
<a:updated>2014-02-12</a:updated>
<a:title type="text">Chickens</a:title>
<a:content type="html">eat 'em all</a:content>
<sortTitle>Chickens</sortTitle>
... other stuffs
<offers>
<offer>
<offerId>8977a259e5a3</offerId>
... other stuffs
<price>0</price>
... other stuffs
</offer>
</offers>
... other stuffs
</a:feed>
and want to get value of <price> but here in my codes:
XDocument doc = XDocument.Parse(xmlString);
var a = doc.Element("a");
var offers = a.Element("offers");
foreach (var offer in offers.Descendants())
{
var price = offer.Element("price");
var value = price.Value;
}
doc.Element("a"); returns null. I tried removing that line offers is also null. what is wrong in my code and how to get value of price? thanks
Here is correct way to get prices:
var xdoc = XDocument.Parse(xmlString);
XNamespace ns = xdoc.Root.GetDefaultNamespace();
var pricres = from o in xdoc.Root.Elements(ns + "offers").Elements(ns + "offer")
select (int)o.Element(ns + "price");
Keep in mind that your document have default namespace, and a is also namespace.
Get the namespace somehow, like
XNameSpace a = doc.Root.GetDefaultNamespace();
or, probably better:
XNameSpace a = doc.Root.GetNamespaceOfPrefix("a");
and then use it in your queries:
// to get <a:feed>
XElement f = doc.Element(a + "feed");
You can also set the namespace from a literal string, but then avoid var.
var xDoc = XDocument.Load(filename);
XNamespace ns = "http://schemas.zune.net/catalog/apps/2008/02";
var prices = xDoc
.Descendants(ns + "offer")
.Select(o => (decimal)o.Element(ns + "price"))
.ToList();
a is a namespace. To get the feed element try this:
XDocument doc = XDocument.Parse(xmlString);
XNamespace a = "http://www.w3.org/2005/Atom";
var feed = doc.Element(a + "feed");

XDocument.Element returns null when parsing an xml string

I have this xml string:
<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="self" type="application/atom+xml" href="/docs" />
<a:updated>2014-02-12</a:updated>
<a:title type="text">Chickens</a:title>
<a:content type="html">eat 'em all</a:content>
<sortTitle>Chickens</sortTitle>
... other stuffs
<offers>
<offer>
<offerId>8977a259e5a3</offerId>
... other stuffs
<price>0</price>
... other stuffs
</offer>
</offers>
... other stuffs
</a:feed>
and want to get value of <price> but here in my codes:
XDocument doc = XDocument.Parse(xmlString);
var a = doc.Element("a");
var offers = a.Element("offers");
foreach (var offer in offers.Descendants())
{
var price = offer.Element("price");
var value = price.Value;
}
doc.Element("a"); returns null. I tried removing that line offers is also null. what is wrong in my code and how to get value of price? thanks
Here is correct way to get prices:
var xdoc = XDocument.Parse(xmlString);
XNamespace ns = xdoc.Root.GetDefaultNamespace();
var pricres = from o in xdoc.Root.Elements(ns + "offers").Elements(ns + "offer")
select (int)o.Element(ns + "price");
Keep in mind that your document have default namespace, and a is also namespace.
Get the namespace somehow, like
XNameSpace a = doc.Root.GetDefaultNamespace();
or, probably better:
XNameSpace a = doc.Root.GetNamespaceOfPrefix("a");
and then use it in your queries:
// to get <a:feed>
XElement f = doc.Element(a + "feed");
You can also set the namespace from a literal string, but then avoid var.
var xDoc = XDocument.Load(filename);
XNamespace ns = "http://schemas.zune.net/catalog/apps/2008/02";
var prices = xDoc
.Descendants(ns + "offer")
.Select(o => (decimal)o.Element(ns + "price"))
.ToList();
a is a namespace. To get the feed element try this:
XDocument doc = XDocument.Parse(xmlString);
XNamespace a = "http://www.w3.org/2005/Atom";
var feed = doc.Element(a + "feed");

How to Load and access data with Linq to XML from XML with namespaces

In my previous question here, I didn’t understand how to solve my problem.
Linq to XML, how to acess an element in C#?
Here is my XML I need to parse:
<root>
<photo>/filesphoto.jpg</photo>
<photo:mtime>12</photo:mtime>
<text>some text</text>
</root>
To access the element I use this code:
var doc = XDocument.Parse(xml.Text);
doc.Descendants("text").FirstOrDefault().Value;
How can I access ?
I have try http://aspnetgotyou.blogspot.com/2010/06/xdocument-or-xelement-with-xmlnamespace.html,
But it is ignored <photo:mtime> and I need to access it.
Please write some code.
Contrary to #BrokenGlass' comments, your XML is not invalid. In fact the technique in the link you provided in your question (for loading namespaces) works fine. Maybe you just didn't change the example for your own needs. Here's a more compact generalization for parsing xml fragments with namespaces into an XElement:
public static XElement parseWithNamespaces(String xml, String[] namespaces) {
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(new NameTable());
foreach (String ns in namespaces) { nameSpaceManager.AddNamespace(ns, ns); }
return XElement.Load(new XmlTextReader(xml, XmlNodeType.Element,
new XmlParserContext(null, nameSpaceManager, null, XmlSpace.None)));
}
Using your exact input:
string xml =
#"<root>
<photo>/filesphoto.jpg</photo>
<photo:mtime>12</photo:mtime>
<text>some text</text>
</root>";
XElement x = parseWithNamespaces(xml, new string[] { "photo" });
foreach (XElement e in x.Elements()) {
Console.WriteLine("{0} = {1}", e.Name, e.Value);
}
Console.WriteLine(x.Element("{photo}mtime").Value);
Prints:
photo = /filesphoto.jpg
{photo}mtime = 12
text = some text
12
Try this: (Your xml is changed a little, see )
string xml = "<root><photo>/filesphoto.jpg</photo><photoMtime>12</photoMtime><text>some text</text></root>";
var doc = XDocument.Parse(xml);
string value = doc.Descendants("text").FirstOrDefault().Value;
MessageBox.Show(value);

How to Parse an XML (using XELement) having multiple Namespace?

I get the followinng Xresponse after parsing the XML document:
<DIDL-Lite
xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/">
<item id="1182" parentID="40" restricted="1">
<title>Hot Issue</title>
</item>
As per the earlier thread, When there is a default namespace in the document, you must parse it as if it were a named namespace. For example.
XNamespace ns = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
var xDIDL = xResponse.Element(ns + "DIDL-Lite");
But in my case I have four different name space. I am not getting any results after using the following query , I am getting the response , Not Yeilding any results:
XNamespace dc = "http://purl.org/dc/elements/1.1/";
var vAudioData = from xAudioinfo in xResponse.Descendants(ns + "DIDL-lite").Elements("item")
select new RMSMedia
{
strAudioTitle = ((string)xAudioinfo.Element(dc + "title")).Trim(),
};
I have no clue whats going on as am new to it. Please help
This is because your item element is in your "ns" namespace. Use:-
XNamespace dc = "http://purl.org/dc/elements/1.1/";
XName didl = ns + "DIDL-lite";
XName item = ns + "item";
XName title = dc + "title";
var vAudioData = from xAudioinfo in xResponse.Descendants(didl).Elements(item)
select new RMSMedia
{
strAudioTitle = ((string)xAudioinfo.Element(title)).Trim(),
};
In these cases I tend to create myself a private class to hold the set of XNames I need to simplify the query code.
You are not getting any results because you are using the wrong namespace. All elements without prefix are in the namespace urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/.
Items in the namespace http://purl.org/dc/elements/1.1/ are prefixed with dc: in the xml document. The fragment does not show any items so it is hart to tell what elements you are looking for.
For example - given the following xml:
<DIDL-Lite
xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/">
<item id="1182" parentID="40" restricted="1">
<title>Hot Issue</title>
<dc:title>Purl Title</dc:title>
</item>
</DIDL-Lite>
And also given the assumption that you want to retrieve both titles the following code should yiedl the results you are looking for:
XNamespace dc= "http://purl.org/dc/elements/1.1/";
XNamespace ns = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
var result = xAudioinfo.Descendants(ns + "title"); // <title></title>
var result2 = xAudioinfo.Descendants(dc + "title"); // <dc:title></dc:title>

Categories

Resources