How to insert a child element into an existing element - c#

I am using a XDocument to write an xml file and I am writing to the document in two different places. After the first write I have
<?xml version="1.0" encoding="utf-8"?>
<suspensedata connectionid="000" customerid="000" name="MyName" />
After the second write I want the file to look like this
<?xml version="1.0" encoding="utf-8"?>
<suspensedata connectionid="560" customerid="131" name="ImgTransfer2327">
<transaction DocumentID="46" SuspenseID="7">
<field id="LocationID">000000015000</field>
<field id="AccountNumber">50000</field>
<field id="AmountPaid">25.00</field>
<field id="CheckAmount">100.00</field>
<field id="CheckNo">000</field>
</transaction>
</suspensedata>
But I can't seem to get the insert done correctly.
I've tried (The name of my XDocument is ValidXml) ValidXml.Root.Add(new Element("transaction"));
and that does not change anything.
I have also tried ValidXml.Element("suspensedata").Add(new XElement("transaction"));
But that did not work either.
How would I add this child element?
EDIT: Both attempts did not produce any other output besides the output on the first try. Also I did make sure to use ValidXml.Save()

I have tried something like this I supposed that the two parts are in 2 files
//xmlfile1 contains the first part
<?xml version="1.0" encoding="utf-8"?>
<suspensedata connectionid="000" customerid="000" name="MyName" />
//this part will be loaded like this
XDocument xDoc = XDocument.Load("xmlfile1.xml");
XElement elt = xDoc.Root;
//and the second file contains the second part
XDocument xDoc2 = XDocument.Load("xmlfile2.xml");
XElement elt2 = xDoc2.Root;
elt.Add(elt2);
xDoc.Save("xmlfile1.xml");
Hope this help

Related

Reading data from XML using C#

I have to read the ordertext ("This is an example text") from this XML File:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<order id="">
<users>
<user id="123456" nick="nick" done="false" />
</users>
<machines>
<machine id="1234" sd="1234" ref="" done="false" />
</machines>
<todos />
<ordertexts>
<ordertext>This is an example text </ordertext>
</ordertexts>
</order>
My C# Code looks like this:
XmlDocument xDoc = new XmlDocument();
xDoc.Load(file);
XmlElement node = (XmlElement)xDoc.SelectSingleNode("/order/ordertexts/ordertext");
When I write the selected data in another XML File it looks like this:
<order>
<oldOrderText>System.Xml.XmlElement</oldOrderText>
</order>
What did I do wrong? Is the XPath incorrect?
I am a C# newbie so I really need every help I can get!
Thanks in advance, geibi
What you're looking for is XmlElement.InnerText.
When you get the node using this:
XmlElement node = (XmlElement)xDoc.SelectSingleNode("/order/ordertexts/ordertext");
You still need to use this:
string neededText = node.InnerText;
to get the value of that node.
Suppose that you're writing the results in a console application. If you try to write the node variable, this way:
Console.WriteLine(node);
Since node is not a string, and it's an XmlElement object, the ToString method of XmlElement is going to be called, which returns the object name, hence your new XML had the result as System.Xml.XmlElement and not the desired text.

Get and Set XML elements with Namespaces

NEWBIE QUESTION.
I haven't worked that much with xml, nothing like this anyway. I have some XML as shown below that I receive which has several namespaces.
I need to read some values, then update others before returning the revised XML with namespaces intact - don't want them removed.
I am given the path to some of the elements like this cred/sub/aa or trip/items/item[0]/customerInfo/custName.
But it seems that namespaces make it difficult to get to those elements so simply.
Does anybody know how I can read some of the values like NON-SMOKING from custPref or get the value CABBAGE from bossman/zz.
Also, I want to be able to then set a value such as custName to say Mr. X.
Any ideas?
Thanks.
<?xml version="1.0" encoding="utf-16" ?>
<A1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<cred xmlns="https://blah-blah.com/?foobar">
<sub>
<aa>Zippo</aa>
<bb>lighter</bb>
</sub>
<reqId>
<cc></cc>
<dateOfBirth></dateOfBirth>
</reqId>
</cred>
<reqName xmlns="http://blah-blah/vader/base">qwerty</reqName>
<reqId xmlns="http://blah-blah/vader/base">12345</reqId>
<machine xmlns="http://blah-blah/vader/base">
<qqq>hello</qqq>
<www>goodbye</www>
<eee>99999</eee>
<rrr>88888</rrr>
</machine>
<monkey xmlns="http://blah-blah/vader/base">alskdjfhg</monkey>
<math xmlns="http://blah-blah/vader/base">
<language></language>
</math>
<trip xmlns="http://blah-blah/simple">
<tripOverview xmlns="http://blah-blah/vader/base">
<description></description>
<cost></cost>
</tripOverview>
<bossman xmlns="http://blah-blah/vader/base">
<zz>CABBAGE</zz>
<yy>BANANA</yy>
<xx>MELON</xx>
<ww>SYRUP</ww>
</bossman>
<items>
<item>
<itemSummary xmlns="http://blah-blah/vader/base">
<description></description>
<cost></cost>
<reference></reference>
</itemSummary>
<customerInfo xmlns="http://blah-blah/vader/base">
<custName></custName>
<custPref>NON-SMOKING</custPref>
</customerInfo>
<seatId xmlns="http://blah-blah/vader/base">1</seatId>
</item>
</items>
</trip>
</A1>
string xml = "<Root><Options></Options></Root>";
var xdocs = XDocument.Parse(xml);
xdocs.Descendants().Where(q => q.Name == "Options").FirstOrDefault().Value = "FoundIt";

Loading multiple XDocuments, and working with its documents

I wrote several lines of code but still can't get over this:
I need to load many xml docs from web library. I don't know how many documents there are so I wonder which loop should I use while loading:
XDocument doc = XDocument.Load("http://" + i);
where -i is identifiers number.
I tried loading until i get document without meaningful content (thought it is the end, the rest are empty), but problem is that there is several Xdocs that are empty in the middle of library.
XML with content looks like
<?xml version="1.0" encoding="utf-8"?>
<OP xmlns="" xmlns:xsi="" xsi:schemaLocation="">
<request verb="GR" identifier="53" metadataPrefix="p"></request>
<GR>
<header>
<identifier>53,number of doc...used for counting</identifier>
</header>
<metadata>
<P xmlns="" xsi:schemaLocation="">
<TITLE>title</TITLE>
<CERTIFICATE NAME="different names">
</CERTIFICATE>
<YEAR>
<DATE>2012-10-18T00:00:00Z</DATE>
</YEAR>
<MINIATURE>
<COPY>
<CNAME>Copy name<CNAME>
<FORMAT>obj/max/dxf/3ds/...</FORMAT>
</COPY>
</MINIATURE>
</metadata>
</GR>
</OP>
XML without content
<?xml version="1.0" encoding="utf-8"?>
<OP xmlns="" xmlns:xsi="" xsi:schemaLocation="">
<request verb="GR" identifier="53" metadataPrefix="p"></request>
Furthermore, I need to do some counting like:
Tot.no. of doc,
No. of docs per certificate <CERTIFICATE>
No. of docs for each year <YEAR><DATE>
No of docs for each format <MINIATURE><COPY><FORMAT>
and my output should look like:
<?xml version="1.0" encoding="UTF-8" ?>
<Statistic>
<DocSum>21220</DocSum>
<Certificates>
<Certificate id=”certificateName”>17098</Certificate>
…
<Certificates>
<Years>
<Year year=”2014”>23</Year>
…
</Years>
<Miniature>
<Format post=”obj”>11723</Format>
…
</Miniature>
</Statistic>
If you could give me some help, hints or tips how to deal with it.
The posted answer by smink to the following thread should get you on the right path.
C# HttpWebRequest command to get directory listing
One of the easiest ways to get a list of the files of a web directory without knowing exactly how many there are or their filenames is by parsing the html of the directory and pulling out the tags.
You can then iterate through these tags and filter them out for the files by extensions that you need. I can provide a more in-depth example if necessary.

Merge two XML files, files having one to many relationship C#

I have two XML files,
1. Contracts
<?xml version="1.0" encoding="UTF-8"?>
<File>
<Contract>
<ContractNo>1</ContractNo>
</Contract>
<Contract>
<ContractNo>2</ContractNo>
</Contract>
</File>
2. Asset
<?xml version="1.0" encoding="UTF-8"?>
<File>
<Asset>
<ContractNo>1</ContractNo>
<SomeData>XXXX</SomeData>
<SomeData2>XXXX</SomeData2>
</Asset>
<Asset>
<ContractNo>1</ContractNo>
<SomeData>YYYY</SomeData>
<SomeData2>YYYY</SomeData2>
</Asset>
<Asset>
<ContractNo>2</ContractNo>
<SomeData>ZZZZ</SomeData>
<SomeData>ZZZZ</SomeData>
</Asset>
</File>
A contract may have one or more assets. XML files are mapped by the contract number. I'm going to merge these two files and
create the below xml
<?xml version="1.0" encoding="UTF-8"?>
<File>
<Contract>
<ContractNo>1</ContractNo>
<Asset>
<SomeData>XXXX</SomeData>
<SomeData2>XXXX</SomeData2>
</Asset>
<Asset>
<SomeData>YYYY</SomeData>
<SomeData2>YYYY</SomeData2>
</Asset>
</Contract>
<Contract>
<ContractNo>2</ContractNo>
<Asset>
<SomeData>ZZZZ</SomeData>
<SomeData2>ZZZZ</SomeData2>
</Asset>
</Contract>
</File>
My approach is to iterate each contract of contract xml and find the contract number, then iterate assets xml and find the asset nodes of the above contract and
merge them to the contract xml
XmlNodeList contractsNodeList = contractsDocument.GetElementsByTagName("Contract");
string contractNumber;
foreach (XmlNode contractNode in contractsNodeList)
{
//get the contract number
contractNumber = contractNode.SelectSingleNode("ContractNo").InnerText;
if (!String.IsNullOrEmpty(contractNumber))
{
XmlNodeList assetsNodeList = assetsDocument.GetElementsByTagName("Asset");
foreach (XmlNode assetNode in assetsNodeList)
{
//checking whether the current asset node has the current contract number
if (assetNode.ChildNodes[0].InnerText == contractNumber)
{
//remove the contract number of the asset node
assetNode.RemoveChild(assetNode.ChildNodes[0]);
//append the asset element to the contract xml
contractNode.AppendChild(contractNode.OwnerDocument.ImportNode(assetNode, true));
}
}
}
}
This code works and generates the required xml. But it not much efficient. I don't have much experiance in working with XML. Please let me know any other ways to
do this. Thank you!
I would personally read in the assets, populating an ILookup<int, XElement> and removing the ContractNo element afterwards (as it's just slightly simpler in LINQ to XML). Then read the contracts, populating the assets from the dictionary. Something like:
XDocument assets = XDocument.Load("assets.xml");
var lookup = assets.Root.Elements("Asset")
.ToLookup(x => (int) x.Element("ContractNo"));
assets.Root.Elements("Asset").Elements("ContractNo").Remove();
XDocument contracts = XDocument.Load("contracts.xml");
foreach (var contract in contracts.Root.Elements("Contract").ToList())
{
var id = (int) contract.Element("ContractNo");
contract.Add(lookup[id]);
}
contracts.Save("results.xml");
Note that this doesn't detect contracts that don't have any assets - they'll just be left as they are.
All of this is doable in the "old" XmlDocument API, but LINQ to XML does tend to make it much simpler.

How to read nested XML using xDocument in Silver light?

Hi currently I have a nested XMl , having the following Structure :
<?xml version="1.0" encoding="utf-8" ?>
<Response>
<Result>
<item id="something" />
<price na="something" />
<?xml version="1.0" encoding="UTF-8" ?>
<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/">
</Result>
<NumberReturned>10</NumberReturned>
<TotalMatches>10</TotalMatches>
</Response>
Any help on how to read this using Xdocument or XMLReader will be really helpfull.
Thanks,
Subhendu
XDocument and XmlReader are both XML parsers that expect a properly formed XML as input. What you have shown is not a XML file. So the first task would be to extract the nested XML and as this is not valid XML you cannot rely on any parser to do this job. You'll need to resort to string manipulation and or regular expressions.
My suggestion would be to fix the procedure generating this invalid XML in the first place. Another suggestion is to never generate a XML file manually but use an appropriate tool for this (XmlWriter, XDocument, ...)

Categories