Duplicate existing element in xml in C# - c#

Please I would like to clone element prijemkaItem from this xml:
The element prijemkaItem is got by this function:
XElement doc = XElement.Load("input.xml");
XmlReader reader = XmlReader.Create("input.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "pri:prijemkaItem")
elementPrijemkaItem = XElement.ReadFrom(reader) as XElement;
break;
}
}
reader.Close()
I would like to put this element behind itself. Please any idea, how can I do this?
Thanks for any advice.

Assuming for simplicity that your Xml structure is the following:
<?xml version="1.0" encoding="utf-8"?>
<dat:dataPack xmlns:dat="datNamespace">
<dat:dataPackItem>
<pri:prijemka xmlns:pri="priNamespace">
<othernode></othernode>
</pri:prijemka>
</dat:dataPackItem>
</dat:dataPack>
If you want to duplicate the pri:prijemka node you can use Linq to Xml:
//using System.Xml.Linq;
//load the xml file
Document doc = XDocument.Load( "D:\\input.xml" );
//get the "dat" namespace
var datNamespace = doc.Root.GetNamespaceOfPrefix( "dat" );
//get "dat:dataPackItem" node
var dataPackItemNode = doc.Root.Element( datNamespace + "dataPackItem" );
//since you don't know the "pri" namespace you can do:
var prijemkaNode = dataPackItemNode.Descendants( )
.Where(x => x.Name.LocalName == "prijemka")
.FirstOrDefault();
//add it to the "dat:dataPackItem" node
dataPackItemNode.Add( prijemkaNode );
//save the xml file
doc.Save( "D:\\input.xml" );
The result is:
<?xml version="1.0" encoding="utf-8"?>
<dat:dataPack xmlns:dat="datNamespace">
<dat:dataPackItem>
<pri:prijemka xmlns:pri="priNamespace">
<othernode></othernode>
</pri:prijemka>
<pri:prijemka xmlns:pri="priNamespace">
<othernode></othernode>
</pri:prijemka>
</dat:dataPackItem>
</dat:dataPack>

Related

delete specific child from xml document

i have an xml file that as shown below
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEtiquette xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Etiquette>
<BgColor>#8075D1C5</BgColor>
<BorderColor>#FF4E5B6F</BorderColor>
<AssociatedAffaireId>
<string>d4689f33-5600-47fe-883d-efcbf5e469c2</string>
<string>203cc4a8-8c24-4a2d-837c-29c7c1f73007</string>
<string>1bae35dd-d501-4d87-bdd4-147fc0ba29d2</string>
</AssociatedAffaireId>
<Label>Ouverte</Label>
</Etiquette>
</ArrayOfEtiquette>
I need to delete only
<string>203cc4a8-8c24-4a2d-837c-29c7c1f73007</string>
this is the code i tried, but its not working,
XDocument xmlSettings = XDocument.Load(chemin + "\\Etiquettes.xml");
if(xmlSettings.ToString().Contains(aff.Id))
{
string newXmlSettings = xmlSettings.ToString().Replace("<string>" +
aff.Id+ "</string>","");
}
xmlSettings.Save(chemin + "\\Etiquettes.xml");
Regards.
You can try with LINQ
//load the xml
var xdoc = XDocument.Load(filePath);
//find and remove
xdoc.Descendants("string")
.Where(x => x.Value == "203cc4a8-8c24-4a2d-837c-29c7c1f73007")
.Remove();
//save it back
xdoc.Save(filePath);

Load data from XML nodes

i have this structure of data:
<?xml version="1.0" encoding="windows-1250"?>
<?xml-stylesheet type="text/xsl" href="usb71105.xsl"?>
<manas:usb xmlns:manas="http://www.manas.info/">
<manas:qr00>
<manas:verzemanas>26052708</manas:verzemanas>
<manas:verzexml>2016.03.29a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/2159405/TRUE</manas:druhtisku>
</manas:qr00>
<manas:qr00>
<manas:verzemanas>26052710</manas:verzemanas>
<manas:verzexml>2016.03.30a</manas:verzexml>
<manas:druhtisku>U_Tisk2P/FALSE</manas:druhtisku>
</manas:qr00>
</manas:usb>
I need to save values of: manas:verzemanas ; manas:verzexml ;
I have this code:
XmlDocument doc = new XmlDocument();
doc.Load("d:\\83116623.XML");
foreach (XmlNode node in doc.DocumentElement)
{
string name = node.Attributes[0].ToString();
}
Have you any ideas please?
You're probably better off with XDocument. Also you need to use the namespace prefix. E.g.:
XNamespace ns = "http://www.manas.info/";
var xdoc = XDocument.Load(#"c:\temp\a\a.xml");
var verze = xdoc.Root.Elements(ns + "qr00")
.Elements(ns + "verzemanas")
.Select(e => e.Value);
verze.ToList().ForEach(v => Console.WriteLine(v));
prints
26052708
26052710

XML node name and attributes are not available

I have the following XML structure:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<values>
<bool key="Chapter_1.Boolean1.value">true</bool>
<string key="Chapter_1.Text1.value">abc</string>
<string key="Chapter_1.Text2.value">Inspection done (2)</string>
<number key="Chapter_1.Number1.value">128</number>
<number key="Chapter_1.Number2.value">34539718</number>
<number key="Chapter_1.Number3.value">3</number>
<datetime key="Chapter_2.Chapter_2_1.DateTime1.value">2020-06-02T09:00:00+03:00</datetime>
<datetime key="Chapter_2.Chapter_2_1.DateTime2.value">2016-02-05T00:00:00+02:00</datetime>
<string key="Chapter_3.Text4.value">52</string>
<string key="Chapter_3.Text5.value">22</string>
<number key="Chapter_3.Number6.value">34539718</number>
</values>
and the following C# code:
var settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Auto;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
using (var xmlReader = new XmlTextReader(xmlFilePath))
{
while (xmlReader.Read())
{
var nodeName = xmlReader.Name;
var attrName = xmlReader.GetAttribute("key");
}
}
The problem is that the node name is empty and there are no attributes for the following keys:
Chapter_1.Text1.value
Chapter_1.Number1.value
Chapter_3.Text5.value
Anyone has any idea what could be the problem?
The code worked well here, I was able to access all xml tags and attributes.
Maybe you're confused because at each xmlReader.Read() it reads only one part of the tag. So to read all the tag with key "Chapter_1.Text1.value", first it reads a tag with name string and key "Chapter_1.Text1.value", then it reads something without a name, without a attribute, but with value "abc" and then it reads the tag closing with name string, but no attribute and no value.
It would be easier to use Xml to Linq :
var xml = XDocument.Load(__PATH_TO_XML__);
var values = xml.XPathSelectElements("/values/*")
.Select(x => new
{
Type = x.Name,
Key = x.Attribute("key"),
Value = x.Value
});
If you want to read the value as well, try this
using (var xmlReader = new XmlTextReader(#"yourxmlfile"))
{
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
var nodeName = xmlReader.Name;
var attrName = xmlReader.GetAttribute("key");
Console.WriteLine(nodeName);
Console.WriteLine(attrName);
}
if (xmlReader.NodeType==XmlNodeType.Text)
{
Console.WriteLine(xmlReader.Value);
}
}
}

Best way to index, search and store information in C#

I'm writing an application which will need to index and store information about files fast. I'm currently using XML to store the information using this code:
XmlTextWriter xtw;
xtw = new XmlTextWriter(FilePath, Encoding.UTF8);
xtw.WriteStartDocument();
xtw.WriteStartElement("ApplicationIndex");
xtw.WriteEndElement();
xtw.Close();
XmlDocument xd = new XmlDocument();
FileStream lfile = new FileStream(FilePath, FileMode.Open);
xd.Load(lfile);
XmlElement cl = xd.CreateElement("Application");
cl.SetAttribute("Name", ApplicationName);
XmlElement na = xd.CreateElement("Path");
XmlText natext = xd.CreateTextNode(ApplicationPath);
na.AppendChild(natext);
cl.AppendChild(na);
XmlElement na1 = xd.CreateElement("UseCount");
XmlText natext1 = xd.CreateTextNode("0");
na1.AppendChild(natext1);
cl.AppendChild(na1);
XmlElement na2 = xd.CreateElement("SearchTerm");
XmlText natext2 = xd.CreateTextNode(ApplicationName.ToLower());
na2.AppendChild(natext2);
cl.AppendChild(na2);
xd.DocumentElement.AppendChild(cl);
lfile.Close();
xd.Save(FilePath);
This works fine for creating the file and storing the data, however I'm having trouble searching through the data quickly as there are several hundred nodes in the document. I've tried using Linq to XML to achieve this using this code:
listBox1.Items.Clear();
var doc = XDocument.Load(filePath);
foreach (var child in doc.Descendants("SearchTerm"))
{
if (child.Value.Contains(textBox1.Text.ToLower()))
{
listBox1.Items.Add(child.Value);
}
}
This is very fast however I can't seem to get any information about the selected node. For example I would like to sort the returned results based upon the UseCount (The higher the count the higher up the list). Is there anyway to do this in XML or any other technique to achieve this?
This is what the XML file looks like:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationIndex>
<Application Name="Google Chrome">
<Path>C:\Program Files\Google\Chrome\Chrome.exe</Path>
<UseCount>0</UseCount>
<SearchTerm>google chrome</SearchTerm>
</Application>
<Application Name="Mozilla Firefox">
<Path>C:\Program Files\Mozilla\Firefox\Firefox.exe</Path>
<UseCount>0</UseCount>
<SearchTerm>mozilla firefox</SearchTerm>
</Application>
</ApplicationIndex>
You can Sort your elements by UseCount in descending order like this:
var doc = XDocument.Load(filePath);
var elements = doc.Descendants("Application")
.OrderByDescending(x => (int)x.Element("UseCount"));
In order to search a record by given SearchTerm you can do the following:
var element = doc.Descendants("Application")
.FirstOrDefault(x => (string)x.Element("SearchTerm") == value);
if(element != null)
{
// record found
}

Renaming Child Nodes in XML file using C#?

I am having a problem renaming child nodes in xml files using c#.
This is my xml file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ZACAC01>
<IDOC BEGIN="1">
<ZACGPIAD SEGMENT="1">
<IDENTIFIER>D000</IDENTIFIER>
<CUST_DEL_NO/>
<CUST_DEL_DATE/>
<TRUCKNO/>
<DRIVERNAME/>
<DRIVERID/>
<RESPONS_OFF/>
<CONFIRM_DATE>20/01/13</CONFIRM_DATE>
<SERIAL_NO>2</SERIAL_NO>
<SERIAL_CHAR/>
<DEL_INFO1/>
<QTY>0</QTY>
<DEL_INFO2/>
<QTY>0</QTY>
<DEL_INFO3/>
<QTY>0</QTY>
<TRANS_COMPANY>0</TRANS_COMPANY>
</ZACGPIAD>
</IDOC>
</ZACAC01>
And below is my requirement:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ZACAC01>
<IDOC BEGIN="1">
<ZACGPIADD SEGMENT="1">
<IDENTIFIER>D000</IDENTIFIER>
<CUST_DEL_NO/>
<CUST_DEL_DATE/>
<TRUCKNO/>
<DRIVERNAME/>
<DRIVERID/>
<RESPONS_OFF/>
<CONFIRM_DATE>20/01/13</CONFIRM_DATE>
<SERIAL_NO>2</SERIAL_NO>
<SERIAL_CHAR/>
<DEL_INFO1/>
<QTY1>0</QTY1>
<DEL_INFO2/>
<QTY2>0</QTY2>
<DEL_INFO3/>
<QTY3>0</QTY3>
<TRANS_COMPANY>0</TRANS_COMPANY>
</ZACGPIADD>
</IDOC>
</ZACAC01>
I am able to change the segment tag <ZACGPIAD> to this <ZACGPIADD> using the following code:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(srcfile);
var root = xmlDoc.GetElementsByTagName("IDOC")[0];
var oldElem = root.SelectSingleNode("ZACGPIAD");
var newElem = xmlDoc.CreateElement("ZACGPIADD");
root.ReplaceChild(newElem, oldElem);
while (oldElem.ChildNodes.Count != 0)
{
newElem.AppendChild(oldElem.ChildNodes[0]);
}
while (oldElem.Attributes.Count != 0)
{
newElem.Attributes.Append(oldElem.Attributes[0]);
}
xmlDoc.Save(desfile);
But I can't change the <QTY> tag to <QTY1>, <QTY2>, <QTY3>
How can I do this?
I think you have the answer right in your code. You can use SelectSingleNode to pull the first <QTY> element with this:
var qtyNode = root.SelectSingleNode("ZACAC01/IDOC/ZACGPIADD/QTY[1]")
then use ReplaceChild on it's parent node. Then do the same for the second and third <QTY> nodes, replacing the '1' with '2' and '3' respectively.
You can use XDocument and operate on XElements which expose setter for node name (so you can simply set new name instead of doing node replacements):
var doc = XDocument.Load(srcfile);
var zacgpidNode = doc.Descendants("ZACGPIAD").First();
zacgpidNode.Name = "ZACGPIADD";
// now rename all QTY nodes
var qtyNodes = zacgpidNode.Elements("QTY").ToArray();
for (int i = 0; i < qtyNodes.Length; i++)
{
qtyNodes[i].Name = string.Format("{0}{1}", qtyNodes[i].Name, i+1);
}
doc.Save(desfile);
Having Descendants("ZACGPIAD").First() might not be suitable if your document structure is different than what you've shown in example. You can use XPathSelectElement method to have more control over what you'll be extracting:
var node = doc.XPathSelectElement("//IDOC[#BEGIN='1']/ZACGPIAD[#SEGMENT='1']");

Categories

Resources