Linq to XML delete parent node - c#

I'm trying to delete a parent from a element in XML.
My XML:
<root>
<Element1 ManagementID="10" />
<Users>
<UserID ManagementID="10">
<Identification IDValue="1" />
<!-- More elements Here -->
</UserID>
</Users>
<!-- More Users elements Here -->
I find my user my its IDValue:
XElement user = (from el in document.Root.Elements("Users").Elements("UserID ").Elements("Identification")
where (string)el.Attribute("IDValue") == myID
select el).FirstOrDefault();
Now, I would like to remove all the user.Parent.Parent
I mean delete the element:
<Users>
<UserID ManagementID="10">
<Identification IDValue="1" />
<!-- More elements Here -->
</UserID>
</Users>
** I'll have many Users elements, that's why first I look for the identification IDValue
I found the solution for who needs it:
I already had the node from my linq so
user.Parent.Parent.Remove()

var user = document.Root
.XPathSelectElements("//UserId")
.FirstOrDefault(userId => userId.Element("Identification").Attribute(XName.Get("IDValue")).Value == myID);

Try this :
List<XElement> users = document.Descendants("Users")
.Where(user => user.Elements("Identification")
.Where(el => (string)el.Attribute("IDValue") != myID)
.Any()).ToList();
XElement element1 = document.Descendants("Element1").FirstOrDefault();
element1.ReplaceNodes(users);

Related

c# sort XElement, with comments

I have an XElement that represents following xml:
<Node>
<Child id="1" /><!-- Comment 1 -->
<Child id="3" /><!-- Comment 3 -->
<Child id="2" /><!-- Comment 2 -->
</Node>
How can I sort the children of Node so that the XElement.ToString() method returns the following?
The comments and text behind the child must be moved along.
<Node>
<Child id="1" /><!-- Comment 1 -->
<Child id="2" /><!-- Comment 2 -->
<Child id="3" /><!-- Comment 3 -->
</Node>
Assuming each element is succeeded by the corresponding comment, try the following:
var xDoc = XDocument.Parse(/* your xml */);
var reordered = xDoc.Root
.Elements("Child")
.Select(el => new {
Element = el,
Comments = el.NodesAfterSelf()
.TakeWhile(n => n.NodeType == XmlNodeType.Comment)
})
.OrderBy(pair => (int)pair.Element.Attribute("id"))
.SelectMany(pair => new [] { pair.Element }.Concat(pair.Comments));
xDoc.Root.ReplaceAll(reordered);
EDIT: edited to allow any (incl. 0) number of comments per element; whitespace was already handled.

Finding a specific xml element containt

Ihave a large xml file and I want to get child element value by giving the parent child element value, I am new in xml file please any help here is my xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<masterController> <uuid>XXXXXXXXXXXXXXXXXXXXXXXXX</uuid>
<channels>
<channel>
<nodeGroups>
<nodeGroup>
<analogNode>
<typeCode>8</typeCode>
<id>1</id>
<sdos>
<sdo>
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<datafield xmlns:xsi="http://www.XXXXX.XXXX/XXXXX/XMLSchema-instance"
xsi:type="intField">
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<offset>2</offset>
<size>1</size>
<readonly>true</readonly>
<isMappedToPdo>false</isMappedToPdo>
<ownerNodeSerial>12102904</ownerNodeSerial>
<ownerSdoIndex>3</ownerSdoIndex>
<data xsi:type="intData">
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">2</value>
<unit></unit>
<min>1</min>
<max>15</max>
</data>
<intValue>2</intValue>
</datafield>
<index>3</index>
<totalbytes>3</totalbytes>
</sdo>
<sdo>
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<datafield xmlns:xsi="http://www.XXXXX.XXXX/XXXXX/XMLSchema-instance"
xsi:type="intField">
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<offset>2</offset>
<size>1</size>
<readonly>true</readonly>
<isMappedToPdo>false</isMappedToPdo>
<ownerNodeSerial>12102905</ownerNodeSerial>
<ownerSdoIndex>4</ownerSdoIndex>
<data xsi:type="intData">
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">16</value>
<unit></unit>
<min>1</min>
<max>15</max>
</data>
<intValue>2</intValue>
</datafield>
<index>3</index>
<totalbytes>3</totalbytes>
</sdo>
</sdos>
</analogNode>
</nodeGroup>
</nodeGroups>
</channel> </channels> </masterController>
I' am trying this but am not geting anything:
XElement root = XElement.Load(Server.MapPath("sample.xml"));
IEnumerable<XElement> masterco = from el in root.Elements("sdo") where (from add in el.Elements("datafield")
where
(string)add.Element("ownerNodeSerial") == TextBox1.Text &&
(string)add.Element("ownerSdoIndex") == TextBox1.Text
select add)
.Any()
select el;
foreach (XElement el in masterco)
{
TextBox3.Text = (string)el.Element("value");
}
I want to get this:
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">16</value>
and be able to update it.
There is one major error in your query:
You are using Elements on root, but you are looking for the tag sdo which is not a direct child of the root tag. You have to use Descendants instead.
Additionally, I think you want to have an OR instead of an AND regarding the text of TextBox1.
Fix it:
var masterco = from el in root.Descendants("sdo")
where (from add in el.Elements("datafield")
where
(string)add.Element("ownerNodeSerial") == TextBox1.Text ||
(string)add.Element("ownerSdoIndex") == TextBox1.Text
select add).Any()
select el;
To actually get the value you want, you should use a different query. There is really no need to select the sdo tag at all.
var value = root.Descendants("datafield")
.Where(x => (string)x.Element("ownerNodeSerial") == TextBox1.Text ||
(string)x.Element("ownerSdoIndex") == TextBox1.Text)
.Select(x => (string)x.Element("data").Element("value"))
.Single();
TextBox3.Text = value;
You can see that I am assuming that in the whole XML document only one matching datafield/data/value entry exists. I derive that information from the way you update your textbox. This would make no sense if there would be multiple tags - the values would overwrite each other in the text box.

LINQ Search attributes on different levels

I would like to search xml file with LINQ technology but have some difficulties.
I would like to find all childs with attribute value and some search condition
My XML (structured data) looks like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<LanguageMenu>
<Menu language="English" name ="Menu" numOfMenus="1">
<MainItem ID="e_mnuMain1" name="File" level="0"></MainItem>
<MainItem ID="e_mnuMain2" name="Edit" level="0"></MainItem>
<MainItem ID="e_mnuMain3" name="Query" level="0"></MainItem>
<MainItem ID="e_mnuMain4" name="Traffic" numOfSubItem="4" level="0">
<SECOND name="Vendors" value="FIN3010" level="1" father="3"></SECOND>
<SECOND name="Buyers" value="FIN3020" level="1" father="3" ></SECOND>
<SECOND name="General ledger" value="FIN3030" level="1" father="3"></SECOND>
<SECOND name="Accounts" value="FIN3040" level="1" father="3">
<THIRD name="Home Accounts" value="FIN3010" level="2" father="5" grantfather="3"/>
<THIRD name="Foreign accounts" value="FIN3050" level="2" father="5" grantfather="3"/>
</SECOND>
</MainItem>
</Menu>
</LanguageMenu>
With LINQ I would like to achieve to find all childrens beginning with Element MainItem that have value FIN3010.
Based on my XML it should return Vendors and Home Accounts.
I would also like to get the parents of that childer so the output I would like to achieve will be like this:
Traffic - Vendors
Traffic - Accounts - Home Accounts
I have stucked with this piece of code:
XElement xelement = XElement.Load("../../xmlFile");
var x = from a in xelement.Descendants("SECONDS")
where a.Attribute("value") != null
&& (string)a.Attribute("value").Value.ToUpper() == txtSifra.Text.ToUpper()
select a;
foreach (XElement xEle in x)
{
//TODO
}
How about this:
var x = from a in xelement.Descendants("MainItem")
.Descendants()
where a.Attribute("value") != null &&
a.Attribute("value").Value
.Equals(txtSifra.Text,
StringComparison.InvariantCultureIgnoreCase)
select a;
foreach (XElement xEle in x)
{
// items will contain all nodes (inclusive) between MainItem and xEle
var items = xEle.AncestorsAndSelf()
.Where(x1 => x1.AncestorsAndSelf("MainItem")
.Any())
.OrderBy(x1 => x1.Ancestors().Count());
var names = items.Attributes("name").Select(a => a.Value).ToArray();
Console.WriteLine(string.Join(" - ", names));
}
The output from this is:
Traffic - Vendors
Traffic - Accounts - Home Accounts

list of node that there attribute

I need a list of all the Attribute ID(the value) of Descendants(Frame) that have an Attribute SecondFeature (Descendants-ObjectClass) that equal Vehicle.
(there is node that have 1 "object", other 2/3 time and other not at all)
this is a part of the code:
<?xml version="1.0" encoding="utf-8" ?>
- <Frame ID="120">
<PTZData Zoom="1.000" />
- <Object ID="5">
<ObjectClass SecondFeature="vehicle" />
</Object>
</Frame>
You can do it with following XPath expression:
var xml = // your XML string here
var doc = XDocument.Parse(xml);
var frameIds = doc.Root.XPathSelectElements(
"//Frame[./Object/ObjectClass[#SecondFeature ='Vehicle']]")
.Select(n => n.Attribute("ID").Value);
Naturally, if your Frame nodes can be present without ID attributes, you'll need extra null checks in .Select.
Alternatively, non-xpath appraoch (but this is IMHO less readable and calls for even more caution):
var frameIds = doc
.Descendants("ObjectClass")
.Where(n => n.Attribute("SecondFeature").Value == "Vehicle")
.Select(n => n.Parent.Parent.Attribute("ID").Value);

Which method should be used instead of descendants() in LINQ to XML?

I am developing asp.net mobile application. I am using XML as a database. I am using the following query for required output. In the XML file I have the collection of MIMIC nodes & inside MIMICS node I have collection of SECTION nodes. One or more more SECTION node contains one or more SECTION nodes ( nested SECTION node) In the SECTION node I have DATAITEM as follows
<MIMIC ID="3" NAME="Network Status">
<SECTIONS>
<SECTION ID="1" NAME="SDA Server 1" HAS-SUBSECTIONS="TRUE">
<DATAITEM NAME="ABC">XYZ</DATAITEM>
<SECTION ID="2" NAME="Top Side">
<DATAITEMS>
<DATAITEM>Not Available</DATAITEM>
</DATAITEMS>
</SECTION>
<SECTION ID="3" NAME="Subsea" HAS-SUBSECTIONS="TRUE">
<SECTION ID="4" NAME="SDA">
<DATAITEMS>
<DATAITEM NAME="SEMA">
<ATTRIBUTE NAME="TYPE" VALUE="?" APPEND-TAG-NAME-BY ="?"/>
<ATTRIBUTE NAME="TagName" VALUE="?"/>
<ATTRIBUTE NAME="OPCTagName" VALUE="?"/>
</DATAITEM>
<DATAITEM NAME="SEMB">
<ATTRIBUTE NAME="TYPE" VALUE="?" APPEND-TAG-NAME-BY ="?"/>
<ATTRIBUTE NAME="TagName" VALUE="?"/>
<ATTRIBUTE NAME="OPCTagName" VALUE="?"/>
</DATAITEM>
</DATAITEMS>
</SECTION>
<SECTION ID="5" NAME="Manifolds" HAS-SUBSECTIONS="TRUE">
For the above XML file I am using following XML query
string MIMIC_ID = "3";
string SECTION_ID = "1";
var QueryResultSet = from Mimic in FieldRoot.Element("USER-INTERFACE-DEFINITION").Element("MIMICS").Descendants("MIMIC")
.Where(e => e.Attribute("ID").Value == MIMIC_ID)
from DataItem in Mimic.Descendants("SECTION")
.Where(e => e.Attribute("ID").Value == SECTION_ID)
.Descendants("DATAITEM")
select DataItem;
In the above XML query I want to access the DATAITEM node only for the SECTION node whose ID=1. But I am getting all the DATAITEM node whose SECTION ID is 2,3,4,5. I think it is because I am using the Mimic.Descendants("SECTION"). Is there any other method which can replace the Mimic.Descendants("SECTION") method so that I can access the DATAITEM node only for SECTION node whose ID=1 ? Can you provide me the code or any link through which I can resolve the above issue
If I understand your input XML correctly (as the sample above doesn't actually show DATAITEM children belonging to SECTION ID=1 (only the nested sections have DATAITEM children), then in your LINQ query instead of .Descendatns("DATAITEM") use:
.Element("DATAITEMS").Elements("DATAITEM")
Descendants will walk the whole subtree of the node you call it on and will return any element with the specified name, since your sections are nested it looks into the nested sections as well.
First in the above XML file there is need to add ID attribute to the each node of DATAITEMS & SECTION.
Then use the following query
var QueryResultSet = from Mimic in FieldRoot.Element("USER-INTERFACE-DEFINITION").Element("MIMICS").Descendants("MIMIC")
.Where(e => e.Attribute("ID").Value == MIMIC_ID)
from DataItem in Mimic.Descendants("SECTION")
.Where(e => e.Attribute("ID").Value == SECTION_ID)
.Descendants("DATAITEM").Where(e =>
e.Parent.Attribute("ID").Value == SECTION_ID)
select DataItem;
In the above query the following part
.Descendants("DATAITEM").Where(e => e.Parent.Attribute("ID").Value == SECTION_ID)
checks for the parent node which can be either SECTION node or DATAITEMS node. You must be careful that the node SECTION & DATAITEMS must have the simialr ID. In these two nodes, SECTION ID is acting as the primary key & DATAITEMS ID is acting as a foreign key. Thus whether DATAITEM are placed below SECTION node or below DATAITEMS node, the above query find out all the required DATAITEM node with the condition SECTION ID=1 or any SECTION ID you want to specify.

Categories

Resources