XmlDocument rearrange XmlNodes C# - c#

I have an XML Document that stores all sorts of information about users of a system. Utlimately, the nodes that I am intersted in I hae outined below.
So, there is a user that has many user contents - I have included just books as an example.
<?xml version="1.0" encoding="UTF-8"?>
<user>
<userProperties>
<alias val="userAliasOne"/>
<id val="3423423"/>
</userProperties>
<userContent>
<userBooks>
<genre>
<book>
<title>Dummy Value</title>
</book>
</genre>
</userBooks>
</userContent>
</user>
I need to somehow restructure the XML, using XmlDocument and XmlNode so that it matches the below. (userBooks to become root node but all contents of userBooks - /genre/book/title - to stay inside userContent).
<?xml version="1.0" encoding="UTF-8"?>
<userBooks>
<user>
<userProperties>
<alias val="userAliasOne"/>
<id val="3423423"/>
</userProperties>
<userContent>
<genre>
<book>
<title>Dummy Value</title>
</book>
</genre>
</userContent>
</user>
</userBooks>
I've tried selecting the single nodes and cloning them, then appending the clone to the parent and removing the child that's no longer required. It became very long and convoluted and I couldn't get it to work. There must be a more elegant solution that I am not aware of.
Any help appreciated.
Thanks.

Using XML Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<XElement> userBooks = doc.Descendants("userBooks").ToList();
foreach(XElement userBook in userBooks)
{
userBook.ReplaceWith(userBook.Element("genre"));
}
}
}
}
​

Here's an example for adding a new root element:
using System;
using System.Xml;
class Test
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("test.xml");
var originalRoot = doc.DocumentElement;
doc.RemoveChild(originalRoot);
var newRoot = doc.CreateElement("userBooks");
doc.AppendChild(newRoot);
newRoot.AppendChild(originalRoot);
doc.Save(Console.Out);
}
}
Try using the same approach for "removing" the userBooks element in the original - remove the element from its parent, but then add all the child nodes (of userBooks) as new child nodes of the original parent of userBooks.

Related

ArgumentException: The node to be inserted is from a different document context

I've searched Stackoverflow on this question, as well as other forums but no one seems to be making this the way I'm making.
By this I mean, in my code, instead of using XMLNode, I'm using XMLElement.
So, without further ado, my intention is to save in an already existing XML Document, a new Element is a child of other existing Elements besides the root.
This is an example on my XML File:
<ROOT>
<NOT_THIS_ONE>
</NOT_THIS_ONE>
<THIS_ONE>
</THIS_ONE>
</ROOT>
So, this is my code:
//XML File
TextAsset repository = Resources.Load("Repository") as TextAsset;
//Create XML Reference
XmlDocument xmlDocument = new XmlDocument();
//Load XML File into XML Reference
xmlDocument.LoadXml(repository.text);
//Root Node
XmlNode statsNode = GetRootNode();
//Get History Node
XmlNode thisOneNode = statsNode.ChildNodes.Item(1);
The GetRootNode() function is this:
//Create Xml Reference
XmlDocument xmlData = new XmlDocument();
//Load Xml File into Xml Reference
xmlData.LoadXml(repository.text);
//Get Root Node
return xmlData.ChildNodes.Item(1);
The thisOneNode gets the <THIS_ONE> Element as a Node (at least that's what I think it does).
Later on, I do this:
XmlElement childOfThisOne = xmlDocument.CreateElement("CHILD");
XmlElement pointsSession = xmlDocument.CreateElement("POINTS");
pointsSession.InnerText = points.ToString();
childOfThisOne.AppendChild(pointsSession);
thisOneNode.AppendChild(childOfThisOne);
xmlDocument.Save("Assets/Resources/GamePoints.xml");
And my intention with this would be something like:
<ROOT>
<NOT_THIS_ONE>
</NOT_THIS_ONE>
<THIS_ONE>
<CHILD>
<POINTS>102</POINTS>
</CHILD>
</THIS_ONE>
</ROOT>
But I get the error in the title: "ArgumentException: The node to be inserted is from a different document context."
And the line in question is this: thisOneNode.AppendChild(childOfThisOne);
Now, where I've searched and the articles I found, people were using XmlNode and even used an xmlDocument.ImportNode(); I tried that too and the same error occurred. Now, I don't how to fix this and I'm requesting your help on this one.
Thank you for your time and happy holidays!
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
#"<ROOT>
<NOT_THIS_ONE>
</NOT_THIS_ONE>
<THIS_ONE>
</THIS_ONE>
</ROOT>";
XDocument doc = XDocument.Parse(xml);
XElement thisOne = doc.Descendants("THIS_ONE").FirstOrDefault();
thisOne.Add(new XElement("CHILD", new XElement("POINTS", 102)));
doc.Save("Assets/Resources/GamePoints.xml");
}
}
}

I need to read xml file data but due to attribute it does not work

i want to read xml file but due to Document node attribute it did not read file.
Code C#:
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(HttpContext.Server.MapPath("~/Content/Images/MMS-CREATE-ALLA-ALLAH2H1-23102018-000170-INP.xml"));
XmlNode settings = xmldoc.SelectSingleNode("Document[#xmlns='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']/MndtInitnReq/GrpHdr");
stu.BranchName = settings.SelectSingleNode("MsgId").InnerText;
XML FIle:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.009.001.01">
<MndtInitnReq>
<GrpHdr>
<MsgId>10005226074</MsgId>
<CreDtTm>2018-10-23T15:20:56</CreDtTm>
</GrpHdr>
</MndtInitnReq>
</Document>
You have a namespace that must be used to get the data. Try Xml Linq :
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication75
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace ns = doc.Root.GetDefaultNamespace();
string msgId = (string)doc.Descendants(ns + "MsgId").FirstOrDefault();
XElement xCreDtTm = doc.Descendants(ns + "CreDtTm").FirstOrDefault();
//will give 1/1/01 when null
DateTime CreDtTm = xCreDtTm == null ? new DateTime() : (DateTime)xCreDtTm;
}
}
}
I don't think loading this xml should be a problem. I verified that by loading the xml you posted in an XmlDocument object.
However I think, your xpath to get "settings" node should have xml namespace in all tags after Document.
So the xpath should be "/[local-name()='Document' and namespace-uri()='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']/[local-name()='MndtInitnReq' and namespace-uri()='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']/*[local-name()='GrpHdr' and namespace-uri()='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']"

XmlDocument.SelectNodes and XPath Navigation

I have XML code that looks similar to this:
<BookStore xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Book>
<bookGenre>Fantasy</bookGenre>
<bookTitle>A Storm of Swords</bookTitle>
<authorInformation>
<authorId>12345</authorId>
<authorName>
<firstName>George</firstName>
<middleInitial>R.R.</middleInitial>
<lastName>Martin</lastName>
</authorName>
</authorInformation>
</Book>
<customer>
<customerData />
</customer>
</BookStore>
The <customer>node may or may not have child nodes, depending on user input.
I am trying to use XmlDocument.SelectNodes and XPath navigation to select <BookStore>, <customer>, and any nodes contained within <customer>.
I have been looking around and reading about XPath and .SelectNodes for a few hours but still don't seem to fully understand how they work. Would anyone have an explanation as to how to use them or how I could use them in my situation? If there are other ways to go about solving my problem I'm open to those too! (I am using C#)
EDIT: here's what I tried based on the stuff I read
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlStr);
XmlNode root = doc.DocumentElement;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlNodeList nodeList = root.SelectNodes("descendant::customer:child::Node");
doc.Save(Console.Out);
Try xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication62
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement customer = doc.Descendants("customer").FirstOrDefault();
Boolean children = customer.HasElements;
}
}
}

Reading xml data from file on desktop

Hello and today I want to find out how I can read an xml file in the following way, I have not been able to find ANYTHING like this or anythig simulaur to how I want to do this that works. I have an xml file with the following content format that has been disabled below this.
<smallusers>
<user id="1">
<name>John</name>
<motto>I am john, who are you?</motto>
</user>
<user id="2">
<name>Peter</name>
<motto>Hello everyone!</motto>
</user>
</smallusers>
<bigusers>
<user id="3">
<name>Barry</name>
<motto>Earth is awesome</motto>
</user>
</bigusers>
How can I put that into 2 string lists in csharp
Load it as a text file into a string or StringBuilder.
prefix it with <xml> and end it with </xml>
then use XmlDocument to load your xml
XML can have only one root tag. You input has more than one root. So you have to wrap your XML in a root like code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
string input = File.ReadAllText(FILENAME);
input = string.Format("<Root>{0}</Root>", input);
XElement root = XElement.Parse(input);
}
}
}
​

How to add Process Instruction to an XML file in C#

How can I add a process instruction to ~50 xml files?
<?xml-stylesheet type="text/xsl" href="Sample.xsl"?>
If I append the node, it is added to the end of the file but it needs to be first.
I would use LINQ to XML:
using System;
using System.Xml.Linq;
public class Test
{
static void Main()
{
XDocument doc = XDocument.Load("test.xml");
var proc = new XProcessingInstruction
("xml-stylesheet", "type=\"text/xsl\" href=\"Sample.xsl\"");
doc.Root.AddBeforeSelf(proc);
doc.Save("test2.xml");
}
}

Categories

Resources