Remove specific nodes under the XML root? - c#

My XML is below;
<XML ID="Microsoft Search Thesaurus">
<thesaurus xmlns="x-schema:tsSchema.xml">
<diacritics_sensitive>1</diacritics_sensitive>
<expansion>
<sub>Internet Explorer</sub>
<sub>IE</sub>
<sub>IE5</sub>
</expansion>
<expansion>
<sub>run</sub>
<sub>jog</sub>
</expansion>
</thesaurus>
</XML>
I want to remove the "expansion" nodes from the XML. After removing process, it would be like that;
<XML ID="Microsoft Search Thesaurus">
<thesaurus xmlns="x-schema:tsSchema.xml">
</thesaurus>
</XML>
My code is below;
XDocument tseng = XDocument.Load("C:\\tseng.xml");
XElement root = tseng.Element("XML").Element("thesaurus");
root.Remove();
tseng.Save("C:\\tseng.xml");
I got an error "Object reference not set to an instance of an object." for line "root.Remove()".
How can I remove the "expansion" nodes from XML file? Thanks.

Use:
Will remove only expansion elements:
XNamespace ns = "x-schema:tsSchema.xml";
tseng.Root.Element(ns + "thesaurus")
.Elements(ns + "expansion").Remove();
Will remove all children of thesaurus:
XNamespace ns = "x-schema:tsSchema.xml";
tseng.Root.Element(ns + "thesaurus").Elements().Remove();

Something like
XElement root = tseng.Element("XML").Element("thesaurus");
tseng.Element("XML").Remove(thesaurus);
You remove a node from it's parent...
if you want to remove just the expansion nodes, then basically you find a remove until tere aren't any in thesaurus, or return a list of them and loop through removing them from their parent thesaurus.

You have no success because your thesaurus have different namespace. You need to specify ti to get it works.
XNamespace ns = "x-schema:tsSchema.xml";
XDocument tseng = XDocument.Parse(xml);
XElement root = tseng.Element("XML").Element(ns + "thesaurus");
root.Elements().Remove();
In general your code valid. The only thing that you need to delete child elements not root to reach results you needed.

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>

How to get value of an XML node?

For the life of me I have not been able to extract the SourcePartyName from this XML document:
<ns0:Visit xmlns:ns0="http://Co.Burgers.Ues">
<ns0:SourcePartyName>NDHARY</ns0:SourcePartyName>
</ns0:Visit>
Using Scott's solution, I've been able to extract the namespace info; however, after dozens of attempts at monkeying with XDocument / XElement, I have not been able to get the desired NDHARY value.
Attempts have included:
xdoc.Descendants(ns + "SourcePartyName").FirstOrDefault()?.Value;
and
xdoc.Element(ns + "SourcePartyName").Value;
How do you get the value of a node from an XDocument?
When using an XDocument you have to go via its Root property.
String xml = #"
<ns0:Visit xmlns:ns0=""http://Co.Burgers.Ues"">
<ns0:SourcePartyName>NDHARY</ns0:SourcePartyName>
</ns0:Visit>
";
XDocument xdoc = XDocument.Parse(xml);
XNamespace ns = "http://Co.Burgers.Ues";
String sourcePartyName = (String)xdoc.Root.Element(ns + "SourcePartyName");

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.

xdocument adding xdocument

I am doing something wrong can't grab shipmentreceiptlineitem to add to first document, do I need to add a namespace?
XDocument xdoc = XDocument.Load("FirstPart.xml");
xdoc.Root.Add(XDocument.Load("RepeatingPart.xml").Element("ShipmentReceiptLineItem").Elements());
xml to grab from:
<tns:ShipmentReceiptNotification xmlns:dl="urn:rosettanet:specification:domain:Logistics:xsd:schema:02.18"
xmlns:tns="urn:rosettanet:specification:interchange:ShipmentReceiptNotification:xsd:schema:02.01">
<tns:ShipmentReceiptLineItem>
</tns:ShipmentReceiptLineItem>
</tns:ShipmentReceiptNotification>
Yes, you need to use the namespace when you try to find the ShipmentReceiptLineItem element. You also need to go from the root element, otherwise your check for Element(...) would only be able to find the root element:
XDocument xdoc = XDocument.Load("FirstPart.xml");
XNamespace tns = "urn:rosettanet:specification:interchange:ShipmentReceiptNotification:xsd:schema:02.01";
xdoc.Root.Add(XDocument.Load("RepeatingPart.xml")
.Root
.Element(tns + "ShipmentReceiptLineItem")
.Elements());
Or splitting it up further:
XDocument repeatingDoc = XDocument.Load("RepeatingPart.xml");
XNamespace tns = "urn:rosettanet:specification:interchange:ShipmentReceiptNotification:xsd:schema:02.01";
var elementsToAdd = repeatingDoc.Root
.Element(tns + "ShipmentReceiptLineItem")
.Elements());
var mainDoc = XDocument.Load("FirstPart.xml");
mainDoc.Root.Add(elementsToAdd);
I find this a lot simpler to read than doing everything in one go. You could potentially get rid of the repeatingDoc variable and do that bit inline, but I definitely wouldn't do the whole thing inline.

Retrieve Element of XDocument by name

I have an XML document. I want to retrieve a specific descendant node of the root node. The root node does not have a namespace, however, the children nodes do, although they are all the same. What is the best way to retrieve this element as an element?
The namespace of the root node doesn't matter.
You can just write
XNamespace ns = "http://...";
var elem = doc.Element(ns + "TagName");
If you don't know the namespace of the children you could match them by LocalName, which refers to the local (unqualified) part of the name.
string name = "purchase";
var query = xml.Descendants()
.Where(e => e.Name.LocalName == name);
This returns an IEnumerable<XElement>. From there you can loop over it or use SingleOrDefault if you expect only one to exist.

Categories

Resources