Generate xml from existing xml without one node - c#

I want to generate an xml from existing one but remove one node by Id:
My xml is:
<PartyList>
<Party Id="1" In="true" Out="true"/>
<Party Id="2" In="true" Out="false"/>
<Party Id="3" In="true" Out="true"/>
</PartyList>
and tried to select the node by using the following but cant remove it:
xmlNode = xmlDoc.SelectSingleNode("/PartyList/Party[#Id='3']"));
how can I remove it? and is there a better way by using linq to xml?

Removing selected element from the XmlDocument can be done as follow :
xmlNode = xmlDoc.SelectSingleNode("/PartyList/Partyx[#Id='3']");
xmlNode.ParentNode.RemoveChild(xmlNode);
xmlDoc.Save("path_for_the_updated_file.xml");
Or using LINQ-to-XML's XDocument :
var doc = XDocument.Load("path_to_your_xml_file.xml");
doc.Root
.Elements("Partyx")
.First(o => (int)o.Attribute("Id") == 3)
.Remove();
doc.Save("path_for_the_updated_file.xml");

Related

How can I get a list of XML nodes by value using C#

I'm trying to get a XmlNodeList from an XmlDocument for nodes that have a certain value, with a view to removing those nodes.
XML:
<List xmlns="http://mynamespace.com/v1">
<Category>2144</Category>
<Title>My Object</Title>
<StartPrice>30.00</StartPrice>
<ReservePrice>-999</ReservePrice>
<BuyNowPrice>-999</BuyNowPrice>
</List>
Preferably I don't want to iterate through every node and check its value. I looked at trying to use LINQ from some examples but I just don't understand it enough to even attempt it.
I feel I'm getting close-ish with XPath (https://www.w3schools.com/xml/xpath_syntax.asp) but I'm beginning to think what I want to do isn't supported.
string xml = UtilityClass.SerializeObject<Listing> ( myListing);
XmlDocument xmlDocument = new XmlDocument ();
xmlDocument.LoadXml ( xml );
XmlElement root = xmlDocument.DocumentElement;
XmlNodeList nodes = root.SelectNodes ( "//*['-999']" );
Am open to other suggestions to get the same result, i.e. remove the nodes with -999 from the Xml document.
Thanks in advance
LINQ to XML is preferred API while dealing with XML in .Net Framework since 2007.
Check it out how easy to achieve what you need in one single statement.
LINQ methods are chained one after another and self-explanatory:
Get all descendants of the root node, taking into account a default namespace.
Whatever the names of the elements.
Where element value is -999.
Convert them to a List<>.
Remove those elements from the XML document.
c#
void Main()
{
XDocument xdoc = XDocument.Parse(#"<List xmlns='http://mynamespace.com/v1'>
<Category>2144</Category>
<Title>My Object</Title>
<StartPrice>30.00</StartPrice>
<ReservePrice>-999</ReservePrice>
<BuyNowPrice>-999</BuyNowPrice>
</List>");
XNamespace ns = xdoc.Root.GetDefaultNamespace();
xdoc.Descendants(ns + "List")
.Elements()
.Where(x => x.Value.Equals("-999"))
.ToList()
.ForEach(x => x.Remove());
Console.WriteLine(xdoc);
}
Output
<List xmlns="http://mynamespace.com/v1">
<Category>2144</Category>
<Title>My Object</Title>
<StartPrice>30.00</StartPrice>
</List>

Select last XML node

I have this XML code:
<AriaGostarInformation>
<MenuInformation>
<MenuNames Name="0" href="default.aspx">home</MenuNames>
<SubMenuNames parentName="1">
fgfgfgfgs
</SubMenuNames>
<SubMenuNames parentName="3">
</SubMenuNames>
</MenuInformation>
<SliderInformation>
<SliderImageAddress>..\..\Img\Hydrangeas.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Jellyfish.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Koala.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Lighthouse.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Penguins.jpg,</SliderImageAddress>
<SliderImageAddress>..\..\Img\Tulips.jpg,</SliderImageAddress>
</SliderInformation>
<LastProductInformation>
<Product Name="147">
<Subject>
</Subject>
<ProductImageAddress>http://localhost:1209/ckeditor/plugins/imagebrowser/browser/Hydrangeas.jpg</ProductImageAddress>
<ProductDes>
<p><span style="color:#FFA07A;">qwqweqweqe</span>qwe</p>
<p><span style="font-size:11px;">qweqweqw</span>e</p>
</ProductDes>
</Product>
<Product Name="dsa">
<Subject>salm</Subject>
<ProductImageAddress>http://localhost:1209/ckeditor/plugins/imagebrowser/browser/Hydrangeas.jpg</ProductImageAddress>
<ProductDes>
<p>sdADASDASDASDASDASDASD</p>
<p>ASDASDASDADASDASDASDASDA</p>
<p>ASDASDASDASDASDASDASDASDASD</p>
</ProductDes>
</Product>
</LastProductInformation>
</AriaGostarInformation>
I want select last product node in LastProductInformation and get this node's attribute.
My code is:
XmlDocument xdoc = new XmlDocument();
xdoc.Load(AppDomain.CurrentDomain.BaseDirectory + #"\static\css\xml\data.xml");
XmlNode xparent = xdoc.SelectSingleNode("//LastProductInformation");
var b = xparent.SelectSingleNode("/Product[last()]").Attributes["Name"].Value;
but this returns null. What should I do?
Using LINQ to XML
var value = XDocument.Load("path")
.Descendants("Product")
.Last()
.Attribute("Name").Value;
Also you can use XPath with LINQ to XML
var value = XDocument.Load("path")
.XPathSelectElement("//LastProductInformation/Product[last()]")
.Attribute("Name").Value;
Note: Make sure you have a reference to System.Xml.Linq namespace from your project.
You don't have to change to linq.
var b = xparent.SelectSingleNode("//Product")[last()].Attributes["Name"].Value;
The last() works like an index so should be at the end.

Unable to remove root node from an xml document using linq to xml c#

Actullay, I need to get all elements except root node from first xml document and so that I could insert them as child nodes to an element(that has same name as a previous doc's root name) in a new document.
So I have tried various ways to achieve it, one of them is removing the root node of first and then trying to add elements to a new one's as given below:
I have tried the following but could not achieve it.
XDocument testDoc = XDocument.Parse(Mydocument);
testDoc.Descendants().Where(e => e.Name.LocalName == "rootName").Select(m=>m).Single().Remove();
var resultDoc = testDoc;
The above code is giving me an empty "{}" result.
my xml document looks something like the below one's:
<rootName xsi:schemaLocation="" xmlns:xsi="" xmlns="">
<main>
<child>
</child>
<anotherchild>
</anotherchild>
</main>
</rootName>
And another way is getting all the elements of first document as the following:
var resultDoc = testDoc.Descendants(ns + "rootName").Elements();
the above statement is giving me the list of elements in the "testDoc" which
I need to do something like below, I am clueless:
<AnotherDocument xsi:schemaLocation="" xmlns:xsi="" xmlns="">
<firstNode>
<rootName>
<main>
<child>
</child>
<anotherchild>
</anotherchild>
</main>
</rootName>
</firstNode>
Please let me know how to insert those elements in a new document as above if I am correct else let me know the way to resolve this issue.
Thanks in advance.
You can replace content of rootName element in another document with elements from first document root:
var xDoc = XDocument.Parse(Mydocument);
var anotherXDoc = XDocument.Load("anotherdata.xml");
XNamespace ns = "http://..."; // your xml namespance
var rootName = anotherXDoc.Descendants(ns + "rootName").First();
rootName.ReplaceNodes(xDoc.Root.Elements());
By this page_nodes gets all nodes now you can used all node by for each loop
var page_nodes = from p in xdoc.Descendants.Where(e => e.Name.LocalName == "rootName").Select(m=>m).Single().Remove() select p;
foreach (var page_node in page_nodes)
{
//Do stuff
}
Wouldn't removing a root node, remove all its child nodes as well? The result you are getting is to be expected I think. You should probably get all the children of the root and copy them to your new document.

Get specific values from Xml

I don't how to extract the values from XML document, and am looking for some help as I'm new to C#
I am using XmlDocument and then XmlNodeList for fetching the particular XML document
Here is my code
XmlNodeList XMLList = doc.SelectNodes("/response/result/doc");
And my XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<result>
<doc>
<long name="LoadID">494</long>
<long name="EventID">5557</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
<doc>
<long name="LoadID">774</long>
<long name="EventID">5558</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
</result>
</response>
In this i have to fetch every the XMLData data that is under every doc tag and i have to fetch last doc tag EventID.
var xml = XDocument.Parse(xmlString);
var docs = xml.Root.Elements("doc");
var lastDocEventID = docs.Last()
.Elements("long")
.First(l => (string)l.Attribute("name") == "EventID")
.Value;
Console.WriteLine ("Last doc EventId: " +lastDocEventID);
foreach (var doc in docs)
{
Console.WriteLine (doc.Element("str").Element("TransactionDate").Value);
}
prints:
Last doc EventId: 5558
2014-05-28T14:17:31.2186777-06:00
2014-05-28T14:17:31.2186777-06:00
You can use two XPath expressions to select the nodes you want. To answer each part of your question in turn:
To select all of the XMLData nodes:
XmlNodeList XMLList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
To select the last EventId:
XmlNode lastEventIdNode =
doc.SelectSingleNode("/response/result/doc[position() =
last()]/long[#name='EventID']");
If not all doc nodes are guaranteed to have an event id child node, then you can simply:
XmlNodeList eventIdNodes =
doc.SelectNodes("/response/result/doc[long[#name='EventID']]");
XmlNode lastNode = eventIdNodes[eventIdNodes.Count - 1];
That should give you what you've asked for.
Update;
If you want the XML data inside each strXml element, you can use the InnerXml property:
XmlNodeList xmlList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
foreach(XmlNode xmlStrNode in xmlList)
{
string xmlInner = xmlStrNode.InnerXml;
}
There's one result tag short in your xml.
Try using this. It's cleaner too imho
XmlNodeList docs = doc.SelectSingleNode("response").SelectSingleNode("result").SelectNodes("doc");
Then you can use a combination of SelectSingleNode, InnerText, Value to get the data from each XmlNode in your list.
For example if you want the EventID from the first doc tag:
int eventID = int.Parse(docs[0].SelectSingleNode("long[#name='EventID']").InnerText);

Inserting XML Fragment after last specific node/element

I want to add an XML fragment to the last element to an XML document and I having problems i.e. the error I get is:
"The reference node is not a child of
this node".
So my existing XML document looks like this:
<MAP>
<LAYER name ="My first Layer">
<DATASET name="foo dataset" />
<SYMBOLOGY>
<SYMBOL colour="red" />
</SYMBOLOGY>
</LAYER>
<LAYER name="My second Layer">
<DATASET name="bar dataset" />
<SYMBOLOGY>
<SYMBOL colour="blue" />
</SYMBOLOGY>
</LAYER>
</MAP>
The XML fragment I want to insert after the last LAYER element is:
<LAYER name="My third Layer">
<DATASET name="whatever dataset" />
<SYMBOLOGY>
<SYMBOL colour="yellow" />
</SYMBOLOGY>
</LAYER>
The code I am using is:
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = inputXML; //which is basically the third layer example - see above.
XmlElement rootElement = xmlDocument.DocumentElement;
XmlNode lastLayerNode = rootElement.SelectSingleNode(#"//LAYER[last()]");
rootElement.InsertAfter(xmlDocFrag, lastLayerNode); //error raised here.
Any ideas on what I'm doing wrong here would be much appreciated. My XPath query seems find and it seems to select the correct last layer it just won't insert after it for some bizarre reason.
UPDATE/SOLUTION - How to do this with XPATH
Finally figured it out in XPath - see the code below, I think it was down to basically not selecting the correct parent node in the first place, it's incorrect to select the last LAYER then try and InsertAfter() on this node. Better to select the level above i.e. MAP then AppendChild(). See below:
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = inputXML;
XmlElement mapElement = (XmlElement)xmlDocument.SelectSingleNode(#"//MAP[last()]");
mapElement.AppendChild(xmlDocFrag);
Thanks to all the replies and help too :)
Taking into consideration that you need this to work with Framework 2.0, here's another solution:
string xml = "<map><layer>1</layer><layer>2</layer></map>";
string addMe = "<layer>3</layer>";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
XmlDocumentFragment xmlDocFrag = xmlDocument.CreateDocumentFragment();
xmlDocFrag.InnerXml = addMe;
XmlElement rootElement = xmlDocument.DocumentElement;
rootElement.AppendChild(xmlDocFrag);
This results in:
<map><layer>1</layer><layer>2</layer><layer>3</layer></map>
Things look pretty good, but I would first try to avoid the xpath selection for the last node, and instead just use this:
rootElement.InsertAfter(xmlDocFrag, rootElement.LastChild);
I had similar issue, I used the ImportNode method to solve it
Here is a small example how you can use it to add node from different xml (stored in string) to your example at desired node in xml tree
string xmlstring =#"<tag>.....</tag>"; // holds xml tree to be appended
XmlDocument xml2 = new XmlDocument();
xml2.Load(#"path_of_main_xml");
XmlDocument xml1 = new XmlDocument();
xml1.Load(new StringReader(xmlString));
// get the node you want to import which in this icase is string
XmlNode elem = xml1.DocumentElement;
// use importNode to import it
XmlNode impnode = xml2.ImportNode(elem,true);
// get the node list of all node of particular tag name
XmlNodeList eNode = xml2.GetElementsByTagName("tag_name_of_parent");
eNode[0].AppendChild(impnode); // append new node
// write back the updates to same file
XmlWriter writer = XmlWriter.Create(#"path_of_main_xml");
xml2.Save(writer);

Categories

Resources