Issue with loading xml in C# containing google kml - c#

I am trying to access the second element in this xml (google kml type) of file and the issue I am having is I get returned null values for my code unless I remove out the <kml xmlns="http://earth.google.com/kml/2.0"> and the related close from the source file. Here is the code I'm using. (mind you this works if I remove the specified line so what I'm looking for is a clean way to process this file without editing the supplied source file.)
XmlDocument doc = new XmlDocument();
doc.Load("2014_q2.xml");
XmlNodeList xnlNodes = doc.SelectNodes("/kml/Document/Folder");
var Node2Use = xnlNodes.Item(1);
here is the top of the source file:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Document>
<open>1</open>
<Folder>
<name>Pts_2014_q3_point Drawing</name>
<Placemark>
<description>HOLTSVILLE</description>
<name>00501</name>
<Style>
<IconStyle>
<color>ffc0c0c0</color>
I have a break on the var Node2Use = xnlNodes.Item(1); line so I can see the contents and thats where I see that I have a zero value where I should have 2 for Folder (like mentioned I get the 2 when I remove out that kml tagged line.)

You need to include the namespace. Something like this:
XmlDocument doc = new XmlDocument();
doc.Load("2014_q2.xml");
XNamespace ns = "http://earth.google.com/kml/2.0";
XmlNodeList xnlNodes = doc.SelectNodes(ns + "/kml/Document/Folder");

Related

How do I edit Node Values in an Xml File with C#

I am trying to change the values in a Farming simulator 22 savegame xml file from C# in visual studio. There are a lot of nodes so I have reduced them to make things easier. I want to know how to replace the value in the node using C# with out having to create and rebuild the xml file from scratch.
the path to the xml file is: (C:\Users\Name\Documents\My Games\FarmingSimulator2022\savegame1\careerSavegame.xml)
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<careerSavegame revision="2" valid="true">
<settings>
<savegameName>My game save</savegameName>
<creationDate>2022-05-03</creationDate>
<mapId>MapFR</mapId>
<mapTitle>Haut-Beyleron</mapTitle>
<saveDateFormatted>2022-08-22</saveDateFormatted>
<saveDate>2022-08-22</saveDate>
<resetVehicles>false</resetVehicles>
</careerSavegame>
You can use the System.Xml.Linq namespace to access the xml file. This will load the file in the memory.
There is one class inside it, XDocument, that represents the xml document.
String filePath = "C:\Users\Name\Documents\My Games\FarmingSimulator2022\savegame1\careerSavegame.xml"
XDocument xdoc = XDocument.Load(filePath);
var element = xdoc.Elements("MyXmlElement").Single();
element.Value = "foo";
xdoc.Save("file.xml");
You can set the element variable as per the one which is needed to be replaced.
Through some research I found the solution to editing the values within the nodes. In this example I only change the value of savegameName, but it will be the same for the rest.
//Routing the xml file
XmlDocument xmlsettings = new XmlDocument();
xmlsettings.Load(#"D:\careerSavegame.xml");
//Setting values to nodes through innertext
String FarmNameSetting = "Martek Farm";
XmlNode savegameNamenode =
xmlsettings.SelectSingleNode
("careerSavegame/settings/savegameName");
savegameNamenode.InnerText = FarmNameSetting;

How to add data after xml in c# and read the xml after?

I've got to create a file with xml header and after that i have to put normal data, smthing like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
Data of the file....
I've already got the code to write it to the file.
Code for that part:
private void setHeader(FileStream output, string nod2, string nod3, string )
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
doc.AppendChild(docNode);
XmlNode header = doc.CreateElement("Header");
doc.AppendChild(header);
XmlNode algorithm = doc.CreateElement("Algorithm");
algorithm.InnerText = "alg";
header.AppendChild(algorithm);
XmlNode node2= doc.CreateElement("nod2");
node2.InnerText = nod2;
header.AppendChild(node2);
XmlNode node3= doc.CreateElement("nod3");
node3.InnerText = nod3;
header.AppendChild(node3);
XmlNode node= doc.CreateElement("node");
header.AppendChild(node);
XmlNode user1 = doc.CreateElement("User");
node.AppendChild(user1);
XmlNode mail = doc.CreateElement("Email");
user1.AppendChild(mail);
XmlNode sessionKey = doc.CreateElement("SessionKey");
user1.AppendChild(sessionKey);
doc.Save(output);
}
It work's pretty well, but when i want to read it with
private void readHeader(FileStream input, out string algorithm)
{
XmlDocument doc = new XmlDocument();
doc.Load(input);
}
I got an error that when the "Data of the file..." starts: "Data on the root level is invalid".
Is there a way to do it with the data after whole xml, or have i to add the data as a node?
This can be done in multiple ways. In comments, you've indicated that the best way is unacceptable for reasons outside the scope of the discussion. For completeness, I'm going to put that one first anyway. Skip down to tl;dr for what I think you'll have to end up doing.
The preferred way to do this is to base64 encode the encrypted data and put it in a CDATA block:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<File>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
<Data><![CDATA[
ICAgIFhtbE5vZGUgYWxnb3JpdGhtID0gZG9jLkNyZWF0ZUVsZW1lbnQoIkFsZ29yaXRobSIpOw0K
ICAgIGFsZ29yaXRobS5Jbm5lclRleHQgPSAiYWxnIjsNCiAgICBoZWFkZXIuQXBwZW5kQ2hpbGQo
YWxnb3JpdGhtKTsNCiAgICBYbWxOb2RlIG5vZGUyPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMiIp
Ow0KICAgIG5vZGUyLklubmVyVGV4dCA9IG5vZDI7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5v
ZGUyKTsNCiAgICBYbWxOb2RlIG5vZGUzPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMyIpOw0KICAg
IG5vZGUzLklubmVyVGV4dCA9IG5vZDM7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5vZGUzKTs=
]]></Data>
</File>
That's the canonical answer to this question.
But you've told me that in your case, a requirement has been imposed that you can't do it that way.
Second choice is MIME (actually, MIME might be the first choice and the above might be the second). But I have a feeling they won't like MIME either.
Third choice, read the file as a string and search for some marker that's inserted between the XML and the binary data, something like a MIME boundary.
tl;dr
If they won't let you add such a marker to the file (and I bet they won't), search for the first occurrence of the substring "</Header>":
var xml = File.ReadAllText(filePath);
var endTag = "</Header>";
var headerXML = xml.Substring(0, xml.IndexOf(endTag) + endTag.Length);
var xdHeader = new XmlDocument();
xdHeader.LoadXml(headerXML);
I tested your code with writing directly to a file, doc.Save(#"c:\temp\test1.xml");
And loading from that file works fine. So there is nothing wrong with your xml document. Check your FileStream. Do you flush and close it properly? Does it have UTF-8 encoding?
What's the input in the node strings. Nothing that is invalid according to xml rules?
After a single root node, only comments and processor instructions can be written to xml. So, you can try to write your data in the comments.
It will look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
...
</Header>
<!-- your data -->
<!-- another data -->
This method has limitations: your data may not contain -- (double-hyphen) and may not end in -.
But it is better, of course, not to do so.

Append XMLDocument to other

I have following two xml strings
<?xml version="1.0"?>
<AccessRequest xml:lang='en-US'>
<AccessLicenseNumber>YOURACCESSLICENSENUMBER</AccessLicenseNumber>
<UserId>YOURUSERID</UserId>
<Password>YOURPASSWORD</Password>
</AccessRequest>
and
<?xml version="1.0" ?>
<RatingServiceSelectionRequest>
<PickupType>
<Code>01</Code>
</PickupType>
<Shipment>
<Description>Rate </Description>
<Shipper>
<Address>
<PostalCode>originzip</PostalCode>
</Address>
</Shipper>
<ShipTo>
<Address>
<PostalCode>destinationzip</PostalCode>
<CountryCode>countrycode</CountryCode>
</Address>
</ShipTo>
<Service>
<Code>11</Code>
</Service>
<Package>
<PackagingType>
<Code>02</Code>
<Description>Package</Description>
</PackagingType>
<Description>Rate Shopping</Description>
<PackageWeight>
<Weight>weight</Weight>
</PackageWeight>
</Package>
<ShipmentServiceOptions/>
</Shipment>
</RatingServiceSelectionRequest>
I want to append second xml string to first one. I tried writing both XmlDocuments to a XmlWriter. But it throws exception "Cannot write XML declaration. XML declaration can be only at the beginning of the document."
Stream stm = req.GetRequestStream();
XmlDocument doc1 = new XmlDocument();
XmlDocument doc2 = new XmlDocument();
doc1.LoadXml(xmlData1);
doc2.LoadXml(xmlData2);
XmlWriterSettings xws = new XmlWriterSettings();
xws.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlWriter xw = XmlWriter.Create(stm, xws))
{
doc1.WriteTo(xw);
doc2.WriteTo(xw);
}
How can I append it as is? Please help
Remove <?xml version="1.0" ?> from second xml string before appending it to first xml string.
I had this problem in the past. The two lines of code below did the job:
var MyDoc = XDocument.Load("File1.xml");
MyDoc.Root.Add(XDocument.Load("File2.xml").Root.Elements());
If you already have strings ready, then please use the Parse function instead of Load.
Please notice I am using the System.Xml.Linq that uses XDocument instead of XmlDocument class.
EDIT
As I understood, you need both documents to be concatenated as is. The problem is that it will eventually leads to an invalid XML document for two reasons :
the document will contain two root nodes: AccessRequest and RatingServiceSelectionRequest. A valid XML document contains only one root node.
There must be only one <?xml version="1.0" ?> XML declaration at the beginning of a document.
If the UPS api your are using is fed with an invalid XML, you unfortunately can not use XML objects. Therefore you will have to use a simple string concatenation to achieve what you want:
var xml = xmlData1 + xmlData2;

XML node madness

I got about 1100 xml files that are read programmatically which works fine, except for one node in around 200 of those files. Redownloaded the data but still the same files aren't working. Maybe someone can help and spot the difference between the working and the non-working.
It's just a matter of one node (rest of that document works for all files) and its inner text.
Working node:
<sequence length="55" mass="6372" checksum="31681CC3DAC0C5D6" modified="2007-01-23" version="2">
MAKGIREKIKLVSSAGTGHFYTTTKNKRTKPEKLELKKFDPVVRQHVIYKEAKIK
</sequence>
Not working node:
<sequence length="394" mass="43314" checksum="6EDA60255F43358F" modified="2007-01-23Z" version="2">
MSKEKFERTKPHVNVGTIGHVDHGKTTLTAAITTVLAKTYGGAARAFDQIDNAPEEKARGITINTSHVEYDTPTRHYAHVDCPGHAD YVKNMITGAAQMDGAILVVAATDGPMPQTREHILLGRQVGVPYIIVFLNKCDMVDDEELLELVEMEVRELLSQYDFPGDDTPIVRGSALKALEGDAEWEAKILELAGFLDSYIPEPERAIDKPFLLPIEDVFSISGRGTVVTGRVERGIIKVGEEVEIVGIKETQKSTCTGVEMFRKLLDEGRAGENVGVLLRGIKREEIERGQVLAKPGTIKPHTKFESEVYILSKDEGGRHTPFFKGYRPQFYFRTTDVTGTIELPEGVEMVMPGDNIKMVVTLIHPIAMDDGLRFAIREGGRTVGAGVVAKVLS
</sequence>
Code that's reading creating the file:
XmlDocument XMLdoc = new XmlDocument();
XMLdoc.LoadXml(Result);
XMLdoc.Save(Datapath);
Code that's reading the file:
XmlDocument XMLdoc = new XmlDocument();
XMLdoc.Load(Datapath);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(XMLdoc.NameTable);
nsmgr.AddNamespace("ns", "http://uniprot.org/uniprot");
Just in case that might be the reason. XML code was verified as well-formed even with the different/broken node.
To make it relevant to others: What can happen in XML files that they won't get read anymore?

How to select xml root node when root node has attribute?

I am trying to select all the child nodes of root node of an xml document using XPath query.
My xml file looks something like following :
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<automotive_industry>
<automotive />
<rail_global_services />
</automotive_industry>
</root>
AND
<?xml version="1.0" encoding="UTF-8" ?>
<root xmlns="http://www.my_department.my_company.com/project_name">
<automotive_industry>
<automotive />
<rail_global_services />
</automotive_industry>
</root>
C# Code to select root node is as follows :
XmlDocument gazetteDocument = new XmlDocument();
gazetteDocument.Load(xmlFilePath);
XmlNodeList allNodes = gazetteDocument.SelectNodes("root");
This code works fine, it selects all the child nodes of root node when root node does not have any attribute that is, it works for 1st xml file but does not work for 2nd xml file because 2nd file has xmlns attribute.
Does anyone knows how to select all the child nodes of root node when root node has attributes??
EDIT :
I found one XPath query : /* This query selects root node no matter whether it has any attribute or not. Once root node is selected, I can iterate through its all the child nodes .
Although the namespace in your XML document is fine, you need to use it in your SelectNodes.
Use this code for your second XML:
XmlDocument gazetteDocument = new XmlDocument();
gazetteDocument.Load(xmlFilePath);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(gazetteDocument.NameTable);
nsmgr.AddNamespace("ns", "http://www.my_department.my_company.com/project_name");
XmlNodeList allNodes = gazetteDocument.SelectNodes("ns:root", nsmgr);
The better way would be to use XDocument and corresponding classes. They are a lot easier to work with.
I don't know the old xml methods of C#, but you could always open the file to read as normal text, and then read to the first node and parse it however you like.
You can use GetElementsByTagName method below are the snippet of my code
XmlDocument gazetteDocument = new XmlDocument();
gazetteDocument.Load(xmlFilePath);
XmlNodeList allNodes = gazetteDocument.GetElementsByTagName("root");

Categories

Resources