select Inner XML nodes which contains nearly same id - c#

This is my XML..
<rootparent>
<root>
...other nodes here.
...
<parent>
<child id="child_1">
.some other nodes ..
</child>
<child id="child_2">
.some other nodes ..
</child>
...other nodes
</parent>
</root>
</rootparent>
I need to select all the child nodes where id like 'child_%' using LINQ to XML.
I got the xpath for this
string xPath="/root/parent/child[id='child_*']";
var x1 =xml.XPathSelectElement(xPath);
var x2 = _sourceDoc.Root.XPathEvaluate(xPath);
but it returns Enumeration yielded no results.

Using xml linq :
string xml =
"<rootparent>" +
"<root>" +
"<parent>" +
"<child id=\"child_1\">" +
"</child>" +
"<child id=\"child_2\">" +
"</child>" +
"</parent" +
"</root>" +
"</rootparent>";
XDocument doc = XDocument.Parse(xml);
List<XElement> children = doc.Descendants("child")
.Where(x => ((string)x.Attribute("id")).StartsWith("child_"))
.ToList();

For starters, your xpath doesn't match the structure of your XML. Your query assumes the root is called root but there's a rootparent and you don't account for it. Since you're just looking for child nodes, you don't even need to reference it, just go through the descendants.
You need to use the appropriate condition. None of your children contains an id element named child_* so naturally you won't get any results. Use the starts-with function and access the id attribute.
//child[starts-with(#id, 'child_')]

Related

Add a parent tag using XML linq

Hello what I want is add another parent tag after the items tag
Here is the example XML:
<parent>
<items>
<book>
<pen></pen>
</book>
</items>
</parent>
and here is the desired output:
<parent>
<items>
<paper>
<book>
<pen></pen>
</book>
</paper>
</items>
</parent>
and here is my code. What's wrong with this?
string xml = "<parent><items>" +
"<book>" +
"<pen>" +
"</pen>" +
"</book>" +
"</items></parent>";
XDocument doc = XDocument.Parse(xml);
Console.WriteLine(doc.ToString());
var books = doc.Descendants("items").Elements().First();
doc.Element("items").Add(new XElement("paper", books));
books.Remove();
Console.WriteLine(doc.ToString());
It only gives me error:
Object reference not set to an instance of an object.
pointing to doc.Element("items").Add(new XElement("paper", books));
the answer below which i marked as checked worked in the example xml
but when i used using the long xml it doesn't work anymore
here is the link of the long xml
http://pastebin.com/nb6Pk8bX
and here is the output
http://pastebin.com/WkZEgUYy
and here is the code im using
XDocument doc = XDocument.Parse(reader);
var books = doc.Descendants("Layout").Elements().First();
books.Ancestors().First().Add(new XElement("Page", books));
books.Remove();
the page tag became the parent. not the layout tag
document>
<Page>
<Layout>
You can do like this, first remove books next add XElement and add again books it's give your destination xml
string xml = "<parent><items>" +
"<book>" +
"<pen>" +
"</pen>" +
"</book>" +
"</items></parent>";
XDocument doc = XDocument.Parse(xml);
Console.WriteLine(doc.ToString());
var books = doc.Descendants("items").Elements().First();
doc.Element("parent").Element("items").Element("book").Remove();
doc.Element("parent").Element("items").Add(new XElement("paper",books));
Console.WriteLine(doc.ToString());
Edit if you dont know first tag name you can use Root
Gets the root element of the XML Tree for this document.
doc.Root.Element("items").Element("book").Remove();
doc.Root.Element("items").Add(new XElement("paper",books));
Edit2 "if the tag after the "items" tag is not a parent tag?"
doc.Descendants("items").Elements("book").Remove();
doc.Descendants("items").First().Add(new XElement("paper", books));
This should work:
XDocument doc = XDocument.Parse(xml);
var books = doc.Descendants("items").Elements().First();
books.Ancestors().First().Add(new XElement("paper", books));
books.Remove();

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.

Inserting XML node at specific position

I have an XML file and I am loading it in Xmldocument. This document has a node with some child nodes like this
<xml here>
<somenode>
<child> </child>
<children></children>
<children></children>
<children></children> // I need to insert it
<children></children> // I need to insert this second time
<children></children>
<children></children>
<child> </child>
<somenode>
<xml here>
here somenode has some children where first and last children node names are same where as other nodes except the first and last node has some diffrent name ( identical to each other ). I am creating a function to insert a node at specific position, I am not sure about the criteria but may be in the mid.
how can I insert node in specific position. I am using XMLnode.appendChild method for insertion
Do I need to rearrange/sort nodes after insertion. Please suggest.
How can I determine what is structure and how should I find where the new node should be added according to current document structure.
Here is a solution without using LINQ to XML. It's implemented as an extension method for the XmlNode class:
public static void InsertAt(this XmlNode node, XmlNode insertingNode, int index = 0)
{
if(insertingNode == null)
return;
if (index < 0)
index = 0;
var childNodes = node.ChildNodes;
var childrenCount = childNodes.Count;
if (index >= childrenCount)
{
node.AppendChild(insertingNode);
return;
}
var followingNode = childNodes[index];
node.InsertBefore(insertingNode, followingNode);
}
Now, you can insert a node at the desired position as simple as:
parentXmlNode.InsertAt(childXmlNode, 7);
you can use XLinq to modify XML document
Following is an example of xml modification
String xmlString = "<?xml version=\"1.0\"?>"+"<xmlhere>"+
"<somenode>"+
" <child> </child>"+
" <children>1</children>"+ //1
" <children>2</children>"+ //2
" <children>3</children>"+ // 3, I need to insert it
" <children>4</children>"+ //4, I need to insert this second time
" <children>5</children>"+
" <children>6</children>"+
" <child> </child>"+
" </somenode>"+
"</xmlhere>";
XElement root = XElement.Parse(xmlString);
var childrens = root.Descendants("children").ToArray();
var third = childrens[3];
var fourth = childrens[4];
third.AddBeforeSelf(new XElement("children"));
fourth.AddBeforeSelf(new XElement("children"));
var updatedchildren = root.Descendants("children").ToArray();
http://www.c-sharpcorner.com/Forums/Thread/55428/how-to-insert-xml-child-node-programmatically.aspx
Cheack it!I guess it will help u.

Remove specific nodes under the XML root?

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.

Linq to XDocument Group by subset

I am looking for a linq to Xdoc query to group by a subset of the XML nodes. I've only been able to get this working to return a subset of the data but I need the entire xml document passed back with only the particular nodes grouped.
<Root>
<Elementname1>
</Elementname1>
<Elementname2>
</Elementname2>
<Elementname3 attrname="test1">
<Child>
</Child>
</Elementname3>
<Elementname3 attrname="test1">
<Child>
</Child>
</Elementname3>
</Root>
This code:
var result =
from row in xDoc.Descendants("Elementname3")
group row by (string)row.Attribute("attrname") into g
select g.First();
returns:
<Elementname3 attrname="test1">
<Child></Child>
</Elementname3>
Expecting:
<Root>
<Elementname1>
</Elementname1>
<Elementname2>
</Elementname2>
<Elementname3 attrname="test1">
<Child>
</Child>
</Elementname3>
</Root>
I understand since descendant element is starting at elementname3; just not sure on how to expound the linq query to start with the root node and group as expected.
Try this:
var result = new XDocument(
new XElement("Root",
from x in doc.Root.Elements()
group x by new { x.Name, Attr = (string)x.Attribute("attrname") } into g
select g.First()
)
);

Categories

Resources