Editing an XML file? - c#

How do I add another element/childnode to a specific parent node in an XML file?
Specifically a new video object to the media node.
I want to turn this:
<?xml version="1.0" encoding="utf-8" ?>
<media>
<Video name="Gladiator">
<English>path1</English>
<Chinese>path2</Cinese>
<French>path3</French>
</Video>
<Video name="Transformers">
<English>path4</English>
<Chinese>path5</Cinese>
<French>path6</French>
</Video>
</media>
into this:
<?xml version="1.0" encoding="utf-8" ?>
<media>
<Video name="Gladiator">
<English>path1</English>
<Chinese>path2</Cinese>
<French>path3</French>
</Video>
<Video name="Transformers">
<English>path4</English>
<Chinese>path5</Cinese>
<French>path6</French>
</Video>
<Video name="Terminator">
<English>path7</English>
<Chinese>path8</Cinese>
<French>path9</French>
</Video>
</media>
If I open an xmlTextwriter, create a new element tag, add attributes and end the element tag; it deletes all previous data in the text file :/

If you use the class XmlTextWriter, you need to read your xml file to get the content before using XmlTextWriter. XmlTextWriter does not load the content of your xml file. That's why all your previous data are gone.
XmlDocument is the simplest way to add a new node.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(filePath);
XmlNode node = FindYourNode(xmlDoc); //Method to find the specific node
node.AppendChild(yourNewXmlNode);
xmlDoc.Save(filePath);
If your xml file is small, the class XmlDocument is perfectly fine. But if you have to manipulate a big xml file, I would suggest to use another class because XmlDocument can hurt your performance.
In that case, I would use a combination of XmlReader and XmlWriter.

I would do something along these lines:
mediaElement.AppendChild(xmlDocument.CreateElement("Video"))
Where mediaElement is a reference to the <media/> element and xmlDocument is of the type XmlDocument.

Related

How to C# Reading xml file

I have an XML file. I want C # with the desktop application. There are similar solutions on the site. But I can't read with the XML I have. How should I proceed about this?
<?xml version="1.0"?>
<RealTimeMetrics SiteId="Site ID">
<Properties>
<Version>3</Version>
<TransmitTime>1581582053</TransmitTime>
<MacAddress>00:b0:9d:23:72:f0</MacAddress>
<IpAddress>192.168.1.99</IpAddress>
<HostName>Cam-19100400</HostName>
<HttpPort>80</HttpPort>
<HttpsPort>443</HttpsPort>
<Timezone>3</Timezone>
<TimezoneName>(GMT 03:00) Nairobi</TimezoneName>
<DST>0</DST>
<HwPlatform>2500</HwPlatform>
<SerialNumber>19100400</SerialNumber>
<DeviceType>0</DeviceType>
<SwRelease>4.1.4005.2249</SwRelease>
</Properties>
<RTReport Date="2020-02-13T11:20:53">
<RTObject Id="0" DeviceId="Demo" Devicename="Demo" ObjectType="0" Name="TEST">
<RTCount TotalEnters="0" TotalExits="0"/>
</RTObject>
</RTReport>
</RealTimeMetrics>
I used simple solution to read and edit XML file:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("path\to\file.xml");
XmlNode node = xmlDoc.SelectSingleNode("//nodeName");
node.InnerText = value;
xmlDoc.Save("path\to\file.xml");
You can load this file, read single node or all nodes, change value of InnerText or Add Atributes, end save this file

C# Skip anything to next tag

I have a log file in xml format like
<log> // skip this node
<?xml version="1.0" encoding="UTF-8"?>
<qbean logger="main-logger">
</qbean>
</log>
<log> // go to this node
</log>
Now ReadToNextSibling("log") throw an exception an I need to skip content of first "log" tag and move to next "log" tag without throwing exception.
Is there a way?
Hint:
Your XML is invalid since the <?xml version="1.0" encoding="UTF-8"?> has to be before the root element. You can search for it and remove it if that fixes your problem. You can use yourXml.Repalce("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "")
You have to create a root element for your XML to be valid for parsing.
Then, you can use the XmlDocument class to parse the XML data that you have and skip anything you want. You would need something like this:
var document = new XmlDocument();
document.LoadXml(yourXml);
document.DocumentElement.ChildNodes[1]

Process namespaces using XmlReader

I have a complex XML file with structure as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="xxx:xxx:xxx:xxx:xxxxx:xxx:xsd:xxxx.xxx.xxx.xx">
<Element1>
<Element2>
<Element2A>xxxxxx</Element2A>
<Element2B>2012-08-29T00:00:00</Element2B>
</Element2>
</Element1>
</Document>
Now I am using XmlReader to read this XML document and process information as follows
XmlReader xr = XmlReader.Create(filename);
while (xr.Read())
{
xr.MoveToElement();
XElement node = (XElement)XElement.ReadFrom(xr);
Console.WriteLine(node.Name);
}
xr.Close();
The problem I am facing is in the output the namespace is prefixed to the ElementName. E.g output
{xxx:xxx:xxx:xxx:xxxxx:xxx:xsd:xxxx.xxx.xxx.xx}Element1
Is there any way I can remove/ handle this as I need to do further filtering using Element names and Child names.
XElement.Name is not (as you might expect) a String, but rather an XName which has a LocalName property, thus:
Console.WriteLine(node.Name.LocalName);
You may want to remove the namespace. One way to remove namespace is to write c# code and other way is to use XSLT transformation as suggested in Remove Namespace
-Milind

how to use XMLTextWriter to write XML node at a specified position

I have an xml file likes below.
<?xml version="1.0" encoding="utf-8" ?>
<Book>
<Title>Title</Title>
<Content>Content</Content>
</Book>
I want to write a new node after 'Content', I know how to use XMLDocument to do that, is there a way to use XMLTextWriter to do that?
You will have to write the whole Xml document, i.e. all elements and attributes and attribute values by using the XmlTextWriter. After you've written the <Content> element, you can write your additional element.
Something like this:
writer.WriteStartDocument();
writer.WriteStartElement("Book");
writer.WriteStartElement("Title");
writer.WriteString("Title");
writer.WriteEndElement();
writer.WriteStartElement("Content");
writer.WriteString("Content");
writer.WriteEndElement();
// insert your new data here
writer.WriteEndElement();
writer.WriteEndDocument();

C# XmlDocument Nodes

I'm trying to access UPS tracking info and, as per their example, I need to build a request like so:
<?xml version="1.0" ?>
<AccessRequest xml:lang='en-US'>
<AccessLicenseNumber>YOURACCESSLICENSENUMBER</AccessLicenseNumber>
<UserId>YOURUSERID</UserId>
<Password>YOURPASSWORD</Password>
</AccessRequest>
<?xml version="1.0" ?>
<TrackRequest>
<Request>
<TransactionReference>
<CustomerContext>guidlikesubstance</CustomerContext>
</TransactionReference>
<RequestAction>Track</RequestAction>
</Request>
<TrackingNumber>1Z9999999999999999</TrackingNumber>
</TrackRequest>
I'm having a problem creating this with 1 XmlDocument in C#. When I try to add the second:
<?xml version="1.0" ?> or the <TrackRequest>
it throws an error:
System.InvalidOperationException: This
document already has a
'DocumentElement' node.
I'm guessing this is because a standard XmlDocument would only have 1 root node. Any ideas?
Heres my code so far:
XmlDocument xmlDoc = new XmlDocument();
XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
XmlElement rootNode = xmlDoc.CreateElement("AccessRequest");
rootNode.SetAttribute("xml:lang", "en-US");
xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement);
xmlDoc.AppendChild(rootNode);
XmlElement licenseNode = xmlDoc.CreateElement("AccessLicenseNumber");
XmlElement userIDNode = xmlDoc.CreateElement("UserId");
XmlElement passwordNode = xmlDoc.CreateElement("Password");
XmlText licenseText = xmlDoc.CreateTextNode("mylicense");
XmlText userIDText = xmlDoc.CreateTextNode("myusername");
XmlText passwordText = xmlDoc.CreateTextNode("mypassword");
rootNode.AppendChild(licenseNode);
rootNode.AppendChild(userIDNode);
rootNode.AppendChild(passwordNode);
licenseNode.AppendChild(licenseText);
userIDNode.AppendChild(userIDText);
passwordNode.AppendChild(passwordText);
XmlElement rootNode2 = xmlDoc.CreateElement("TrackRequest");
xmlDoc.AppendChild(rootNode2);
An XML document can only ever have one root node. Otherwise it's not well formed. You will need to create 2 xml documents and join them together if you need to send both at once.
Its throwing an exception because you are trying to create invalid xml. XmlDocument will only generate well formed xml.
You could do it using an XMLWriter and setting XmlWriterSettings.ConformanceLevel to Fragment or you could create two XmlDocuments and write them out into the same stream.
Build two separate XML documents and concatenate their string representation.
It looks like your node structure always be the same. (I don't see any conditional logic.) If the structure is constant you could define an XML template string. Load that string into an XML Document & do a SelectNode to populate individual nodes.
That may be simpler/cleaner than programatically creating the root, elements & nodes.

Categories