How to Get a specific Value of an XML Node from XDocument - c#

I am asking essentially the same question as found in this post: How to Get XML Node from XDocument with the exception of attempting to do a one-shot return of the CData value in a single line of code. I'm attempting to get the return in the below function to work properly:
private string RetrieveFormattedString(string controlId)
{
return template.Descendants("Template")
.Where(templateNode => templateNode.Value == controlId)
.Where(tmp => tmp.Name == "Format").Select(y => y.Value).ToString();
}
I have the following XML below:
<?xml version="1.0" encoding="utf-8" ?>
<Templates>
<Template>
<Name>NodeName1</Name>
<Parameter Type="TextBox" Name="conferenceID">{__otcConferenceID__}</Parameter>
<Parameter Type="TextBox" Name="conferenceCode">{__otcConferenceCode__}</Parameter>
<Format>
<![CDATA[ <b>NodeName1</b><br /> <table><tr><td>iPhone</td><td>{__otcConferenceID__},#,{__otcConferenceCode__}</td></tr></table>]]>
</Format>
</Template>
<Template>
<Name>NodeName2</Name>
<Parameter Type="TextBox" Name="conferenceID">{__otcConferenceID__}</Parameter>
<Parameter Type="TextBox" Name="conferenceCode">{__otcConferenceCode__}</Parameter>
<Format>
<![CDATA[ <b>NodeName2</b><br /> <table><tr><td>iPhone</td><td>{__otcConferenceID__},#,{__otcConferenceCode__}</td></tr></table>]]>
</Format>
</Template>
</Templates>
I know I'm doing this incorrectly, and was hoping to get a larger set of eyes on it.

private string RetrieveFormattedString(XDocument xDoc, string nodeName)
{
return xDoc.Descendants("Template")
.First(t => t.Element("Name").Value == nodeName)
.Element("Format").Value;
}

Related

Find and substitute values from XML files

I'm trying to automate the replacement of translations from one XML file to another. The original translator set the translation in the wrong files, and I'm trying to restore them back with an automated process. The original files are like this:
<version major="3" minor="6" revision="3" build="1" />
<region id="TranslatedStringKeys">
<node id="root">
<children>
<node id="TranslatedStringKey">
<attribute id="Content" type="28" handle="ls::TranslatedStringRepository::s_HandleUnknown" value="Spanish 1" />
<attribute id="ExtraData" type="23" value="" />
<attribute id="Speaker" type="22" value="" />
<attribute id="Stub" type="19" value="True" />
<attribute id="UUID" type="22" value="AAA" />
</node>
<node id="TranslatedStringKey">
<attribute id="Content" type="28" handle="ls::TranslatedStringRepository::s_HandleUnknown" value="Spanish 2" />
<attribute id="ExtraData" type="23" value="" />
<attribute id="Speaker" type="22" value="" />
<attribute id="Stub" type="19" value="True" />
<attribute id="UUID" type="22" value="BBB" />
</node>
</children>
</node>
</region>
<content contentuid="h5f6c914fg7db0g4763g9731g58a5eb60c6ab" Source="1.lsb" Key="AAA">English1</content>
<content contentuid="h95735cfdgc22cg4d38g9679ge071f18d77aa" Source="1.lsb" Key="BBB">English2</content>
My goal would be to compare the value of the attribute 'value' in the attribute which id="UUID" to the Key of each 'content' node, and if it is the same then substitute the value of each 'content' node with the value of the attribute 'value' in the attribute which id="Content", so that it ends like:
<content contentuid="h5f6c914fg7db0g4763g9731g58a5eb60c6ab" Source="1.lsb" Key="AAA">Spanish 1</content>
<content contentuid="h95735cfdgc22cg4d38g9679ge071f18d77aa" Source="1.lsb" Key="BBB">Spanish 2</content>
I have tried to operate with C# and Xml.Linq but I have lots of errors in the build of my code since my experience with it is very limited.
Thank you for your help and time
In case someone has the same issue, I found a solution to it:
XmlDocument docMain = new XmlDocument();
XmlDocument docCommon = new XmlDocument();
docMain.Load("spanish.xml");
docCommon.Load("COMMON.xml");
foreach (XmlElement elem in docMain.FirstChild)
{
if (elem.GetAttribute("Key") != "")
{
foreach (XmlElement att in docCommon.SelectNodes("descendant::save/region/node/children/node"))
{
XmlNodeList AttList = (XmlNodeList)att.ChildNodes;
XmlElement trans = (XmlElement) AttList.Item(0);
XmlElement UUID = (XmlElement)AttList.Item(4);
if (elem.GetAttribute("Key") == UUID.GetAttribute("value"))
{
elem.InnerText= trans.GetAttribute("value");
}
else { }
}
}
else { }
}
docMain.Save("modified.xml");
Feel free to add suggestions in order to optimise code if you feel like it.

Im trying to make a small program in c# console that reads some parts of the xml file but im getting a error

The error i get is Daya at the root level is invalid. Line 1, position 1.
using System;
using System.Xml;
using System.IO;
namespace XmlReaderConsoleAPP
{
class Program
{
static void Main()
{
XmlDocument xml = new XmlDocument();
xml.LoadXml("c:\\SaintGobain_Pam_20210118.xml");
string _byteOrderMarkUtf8 =
Enconding.UTF8.GetString(Encoding.UTF8.GetPreamble());
if (xml.StartWith(_byteOrderMarkUtf8))
{
var lastIndexOfUtf8 = _byteOrderMarkUtf8.Length - 1;
xml = xml.Remove(0, _byteOrderMarkUtf8.Length - 1);
}
XmlNodeList xnLista = xml.SelectNodes("/Batches/Batch/BatchFields/BatchField/Documents/Document/IndexFields/IndexField/Pages/Page");
foreach(XmlNode xn in xnLista)
{
string formulario = xn["FormTypeName"].InnerText;
string Value = xn["Value"].InnerText;
string FileName = xn["ImportFileName"].InnerText;
Console.WriteLine("Formulário: {0}", formulario, "Value: {1} ", Value, "FilePath: {2}", FileName);
}
}
}
}
And the XML contents are
<ImportSession>
<Batches>
<Batch Name="MSG_SaintGobainPam_20210118" Description="SaintGobain_20210118"
BatchClassName="SAINTGOBAIN - Faturas Notas" Processed="1">
<BatchFields>
<BatchField Name="CAPALOTE" Value="0" />
<BatchField Name="NCONTENTOR" Value="0" />
</BatchFields>
<Documents>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047804" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047804.pdf" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047842" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047842.pdf" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047843" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047843.pdf" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047849" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047849.pdf"/>
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047853" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047853.pdf" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047854" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047854.pdf" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047855" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047855.pdf" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047860" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047860.pdf"/>
ErrorCode="20" ErrorMessage="Illegal file format
(\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047860.pdf)" />
</Pages>
</Document>
<Document FormTypeName="DOC_SaintGobain_Faturas_Notas">
<IndexFields>
<IndexField Name="ETIQUETA" Value="ZE80047861" />
</IndexFields>
<Pages>
<Page
ImportFileName="\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047861.pdf"/>
</Pages>
</Document>
</Documents>
</Batch>
Im asking this because i couldnt find a answer to my question but if there is please link it in the answers.
XML FILE is now added to the post as you can see.
I really dont know why it keeps happening but ye hope you guys can help.
Some suggestions to move forward:
static void Main()
{
XmlDocument xml = new XmlDocument();
// Catch Exception, print message and bail out.
try{
// vv "LoadXml" replaced by "Load"
xml.Load("c:\\SaintGobain_Pam_20210118.xml");
}
catch(Exception ex)
{
Console.WriteLine("OOps: {0}", ex.Message);
return;
}
string _byteOrderMarkUtf8 =
Enconding.UTF8.GetString(Encoding.UTF8.GetPreamble());
if (xml.StartWith(_byteOrderMarkUtf8))
{
var lastIndexOfUtf8 = _byteOrderMarkUtf8.Length - 1;
xml = xml.Remove(0, _byteOrderMarkUtf8.Length - 1);
}
// vv replace XPath expression
XmlNodeList xnLista = xml.SelectNodes(#"//Pages/Page");
foreach(XmlNode xn in xnLista)
{
string formulario = xn["FormTypeName"].InnerText;
string Value = xn["Value"].InnerText;
string FileName = xn["ImportFileName"].InnerText;
// Correct syntax:
Console.WriteLine("Formulário: {0}, Value: {1} ,FilePath: {2}",formulario, Value, FileName);
}
}
Then manually sanitize (for now) the source file:
Delete ErrorCode="20" ErrorMessage="Illegal file format (\\umm\c$\acxmlaid\SaintGobain\20210118\ZE80047860.pdf)" />
And give it another try.

Delete data in XML with C#

I have the following XML File:
<order id="1234">
<users>
<user id="102030" nick="nickname" done="false" />
<user id="123456" nick="nickname" done="false" />
</users>
<machines>
<machine id="123" sd="123" ref="" done="false" />
<machine id="456" sd="456" ref="" done="false" />
<machine id="789" sd="789" ref="" done="false" />
</machines>
</order>
I want to delete the user with the id 102030, so the xml looks like this:
<users>
<user id="123456" nick="nickname" done="false" />
</users>
<machines>
<machine id="123" sd="123" ref="" done="false" />
<machine id="456" sd="456" ref="" done="false" />
<machine id="789" sd="789" ref="" done="false" />
</machines>
</order>
This is my code which doesn't work:
XmlDocument doc = XmlDocument.Load(path);
XmlNodeList nodes = doc.GetElementsByTagName("users");
foreach(XmlNode node in nodes){
foreach(XmlAttribute attribute in node.Attributes){
if(attribute.Name== "id" && attribute.Value == "102030"){
node.RemoveAll();
}
}
}
doc.Save(path);
I am a newbie in C# so I need every help!
Thanks in advance, geibi
XmlNode.RemoveAll() does not remove a node. Instead it:
Removes all the child nodes and/or attributes of the current node.
Thus, instead you need to remove the node from its parent:
node.ParentNode.RemoveChild(node);

Adding Xml Attribute to All elements except root Node

I am trying to add new attribute to my xml files in c#. my xml file format is shown below:
<Root MessageOfRoot="Welcome to Xml">
<Header Size="36">
<Parameter Name="ID" Index="0" Value="23" />
<Parameter Name="Name" Index="4" Value="Uncle Bob" />
<Parameter Name="Number" Index="8" Value="4" />
</Header>
<Body Size="0">
<Parameter Index="0" UnitNumber="0" Name="UnitBarcode" Type="Integer" />
<Parameter Index="4" PromotionId="0" Name="PromotionalUnit" Type="Integer" />
</Body>
</Root>
I want to add new attribute my xml file which should be like:
<Root MessageOfRoot="Welcome to Xml">
<Header Size="36" NewAttr="1">
<Parameter Name="ID" Index="0" Value="23" NewAttr="1"/>
<Parameter Name="Name" Index="4" Value="Uncle Bob" NewAttr="1"/>
<Parameter Name="Number" Index="8" Value="4" NewAttr="1"/>
</Header>
<Body Size="0" NewAttr="1">
<Parameter Index="0" UnitNumber="0" Name="UnitBarcode" Type="Integer" NewAttr="1"/>
<Parameter Index="4" PromotionId="0" Name="PromotionalUnit" Type="Integer" NewAttr="1"/>
</Body>
</Root>
To do that i write the following code but i am having problem with adding newAttr to all nodes. How can i add NewAttr to my new xml file?
XmlDocument doc = new XmlDocument();
doc.Load("Path of xml");
XmlAttribute NewAttr = doc.CreateAttribute("NewAttr ");
countAttr.Value = "1";
XmlWriter writer = XmlWriter.Create("output.xml", settings);
You can use the following command to load the XML file:
XDocument doc = XDocument.Load(#"C:\Users\myUser\myFile.xml");
Then you can invoke a function that recursively accesses all nodes of the XML starting from the children nodes of the Root element:
AddNewAttribute(doc.Root.Elements());
The function can be like so:
public static void AddNewAttribute(IEnumerable<XElement> elements)
{
foreach (XElement elm in elements)
{
elm.Add(new XAttribute("newAttr", 1));
AddNewAttribute(elm.Elements());
}
}
Finally, you can save the XML back to the original file using:
doc.Save(#"C:\Users\myUser\myFile.xml");

How to parse XML file in c#

I have a XML that has a structure similar to this one:
<?xml version="1.0" encoding="UTF-8"?>
<CompanyName>
<AttrContainer>
<Attr type="String">
<Name value="'Name'" />
<Value value="'AttrContainer'" />
</Attr>
<SubContainer>
<AttrContainer value="'WSSMetadata'" />
<AttrContainer>
<Attr type="String">
<Name value="'Name'" />
<Value value="'AttrContainer'" />
</Attr>
<SubContainer>
<WSSMetadata value="'afe2e194-0ce7-4bfc-b446-9623e4fe7189'" />
<AttrContainer>
<Attr type="String">
<Name value="'Name'" />
<Value value="'WSSMetadata'" />
</Attr>
<Attr type="Uuid">
<Name value="'scanID'" />
<Value value="afe2e194-0ce7-4bfc-b446-9623e4fe7189" />
</Attr>
<Attr type="String">
<Name value="'imagePath'" />
</Attr>
<Attr type="String">
<Name value="'imagePathHD'" />
</Attr>
<Attr type="String">
<Name value="'imagePathThumbnail'" />
</Attr>
<Attr type="String">
<Name value="'imagePathGrey'" />
<Value value="'Images/afe2e194-0ce7-4bfc-b446-9623e4fe7189_grey.jpg'" />
</Attr>
<Attr type="String">
<Name value="'imagePathGreyHD'" />
<Value value="'Images/afe2e194-0ce7-4bfc-b446-9623e4fe7189_grey_hd.jpg'" />
</Attr>
<Attr type="String">
<Name value="'imagePathGreyThumbnail'" />
<Value value="'Images/afe2e194-0ce7-4bfc-b446-9623e4fe7189_grey_thumbnail.jpg'" />
</Attr>
</AttrContainer>
</SubContainer>
</AttrContainer>
</SubContainer>
</AttrContainer>
</CompanyName>
and I am trying to parse it using this code (Linq to XML)
var xmlContent = File.ReadAllText(filePathName);
var doc = XDocument.Parse(xmlContent);
var attr = doc.Root.Elements("CompanyName");
var x = attr.ToList();
but it x has no element.
My questions:
What is wrong with this code that I am not able to get the CompanyName element?
How can I get list of all <SubContainer> elements?
When I got the list of <SubContainer> elements, how can I read read and change its content?
I think you want this instead:
var attr = doc.Root.Elements("AttrContainer");
.Elements returns child elements of that name. CompanyName is you root node, and you're trying to search for its children which are AttrContainer.
What is wrong with this code that I am not able to get the companyname element?
The root element of your xml is CompanyName. So what your code is doing, it's essentially asking 'give me all CompanyName elements that are children of my root CompanyName element'. Hence the list is empty.
how can I get list of all SubContainer elements.
You can use
var subContainers = doc.Root.Descendants("SubContainer");
when I got the list of SubContainer elements, how can I read read and change its content?
foreach (var subContainer in subContainers)
{
foreach (var attrContainer in subContainer.Elements("AttrContainer"))
{
var attr = attrContainer.Elements("Attr").FirstOrDefault();
if (attr != null)
{
var oldValue = attr.Attribute("type").Value;
attr.Attribute("type").Value = "something completely different";
}
}
}
This reads and changes the type on each first Attr element (assuming one exists) in all AttrContainers in all SubContainers - hopefully you can derive something meaningful out of that.
doc.Root returns the element <CompanyName>, so further selecting elements named CompanyName won't return any elements. You're effectively trying to select all <CompanyName> elements that are children of <CompanyName>.
This code will select all <SubContainer> elements no matter their depth. I'm suggesting this because your example XML has several <SubContainer> elements.
// Read all Attr elements
IEnumerable<XElement> subContainerElements = doc.Root.Descendants("SubContainer");
foreach (XElement subContainerElement in subContainerElements)
{
// Work with <SubContainer> element here
}

Categories