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.
Related
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);
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");
I'm building a database with meets, clubs, results and a lot more for swimmers in the Netherlands. Due to some changes in the data i am receiving i'm running into a problem with duplicate values in the XML files i am reading.
Here is part of an XML file that causes problems :
<LENEX version="3.0">
<MEETS>
<MEET name="Speedowedstrijd 2012 - 2013 deel 1">
<CLUB name="AZVD" type="CLUB" nation="NED" region="08" code="08-004">
<OFFICIALS>
<OFFICIAL nation="NED" gender="M" officialid="2329" lastname="xx">
<CONTACT email="xx" phone="xx" country="NL" />
</OFFICIAL>
</OFFICIALS>
</CLUB>
<CLUB name="A.Z.V.D." type="CLUB" nation="NED" region="8" code="08-004">
<ATHLETES>
<ATHLETE nation="NED" gender="M" athleteid="2358" license="xx" lastname="xx">
<RESULTS>
<RESULT eventid="1167" resultid="2359" swimtime="00:03:09.69">
<SPLITS>
<SPLIT distance="50" swimtime="00:00:40.71"/>
<SPLIT distance="100" swimtime="00:01:30.71"/>
</SPLITS>
</RESULT>
</RESULTS>
</ATHLETE>
</ATHLETES>
</CLUB>
</MEET>
</MEETS>
</LENEX>
Now the reading of the xml file is not a problem, using XDocument i get all the nodes, childs etc.
However, when i write the values to my database i get an keyconstraint error on the table Club_Meet. This table holds the link between the clubs table and the meet table and each conbination must be unique. As both clubs in the example above are pointing to the same club in my database (unique code = 08-004, i am trying to write the same values to the database twice, causing the error.
So waht i want to do is when i go through the xml file and find a club : check if this club was already found in this XML before and if so hang the childnodes under that first club-node.
The result of this action should be (internally) :
<LENEX version="3.0">
<MEETS>
<MEET name="Speedowedstrijd 2012 - 2013 deel 1">
<CLUB name="AZVD" type="CLUB" nation="NED" region="08" code="08-004">
<OFFICIALS>
<OFFICIAL nation="NED" gender="M" officialid="2329" lastname="xx">
<CONTACT email="xx" phone="xx" country="NL" />
</OFFICIAL>
</OFFICIALS>
<ATHLETES>
<ATHLETE nation="NED" gender="M" athleteid="2358" license="xx" lastname="xx">
<RESULTS>
<RESULT eventid="1167" resultid="2359" swimtime="00:03:09.69">
<SPLITS>
<SPLIT distance="50" swimtime="00:00:40.71"/>
<SPLIT distance="100" swimtime="00:01:30.71"/>
</SPLITS>
</RESULT>
</RESULTS>
</ATHLETE>
</ATHLETES>
</CLUB>
</MEET>
</MEETS>
</LENEX>
Note that the second club-node <CLUB name="A.Z.V.D." type="CLUB" nation="NED" region="8" code="08-004"> is removed completely, i dont need anything from that one.
How do i move the child nodes from one club to another and delete the empty club ?
Anyone that can point me in the right direction ?
(Hope this all makes some sense....)
OK so if you want to work strictly with the manipulation of your XML document, you can use the following extension method which I created.
public static class XmlExtensions
{
public static IEnumerable<XElement> CombineLikeElements(this IEnumerable<XElement> source, Func<XElement, object> groupSelector)
{
// used to record the newly combined elements
List<XElement> priElements = new List<XElement>();
// group the current xml nodes by the supplied groupSelector, and only
// select the groups that have more than 1 elements.
var groups = source.GroupBy(groupSelector).Where(grp => grp.Count() > 1);
foreach(var grp in groups)
{
// get the first (primary) child element and use it as
// element that all the other sibling elements get combined with.
var priElement = grp.First();
// get all the sibling elements which will be combined
// with the primary element. Skipping the primary element.
var sibElements = grp.Skip(1);
// add all the sibling element's child nodes to the primary
// element.
priElement.Add(sibElements.Select(node => node.Elements()));
// remove all of the sibling elements
sibElements.Remove();
// add the primary element to the return list
priElements.Add(priElement);
}
// return the primary elements incase we want to do some further
// combining of their descendents
return priElements;
}
}
You would use the extension method as follows:
XDocument xmlDoc = XDocument.Parse(xml);
xmlDoc
// Combine all of the duplicate CLUB nodes under each MEET node
.Descendants("MEET").Descendants("CLUB").CombineLikeElements(node => node.Attribute("code").Value);
And it would return the results that you requested.
I have the extension method returning a list of the XElements which everything was combined into in case you want to combine their child nodes. For example if after combining your identical CLUB elements, one or more of the CLUBs ends up having two or more ATHLETES or OFFICIALS nodes you can could combine those easily as well by doing the following:
xmlDoc
// Combine all of the duplicate CLUB nodes under each MEET node
.Descendants("MEET").Descendants("CLUB").CombineLikeElements(node => node.Attribute("code").Value)
// Combine all of the duplicate ALTHLETES or OFFICIALS nodes under the newly combined CLUB nodes
.Elements().CombineLikeElements(node => node.Name);
I want to search through XML Using GetElementId .
I have an XML file with attributes associated with each element. Elements name may defer but each element will have unique Id.
For example:
<root>
<secondRoot>
<Person UniqueID='A112' Name='Fred'><FeMale>I am Female</FeMale></Person>
<Person UniqueID='A111'><Male>I am male</Male></Person>
<Person SSN='A222' Name='Tom'/>
<Customer id='A111'/>
<Customer id='A222334444'/>
<Team members='A222334444 A333445555'/>
<Random/>
</secondRoot>
</root>
In the above XML i have UniqueID attribute associated with several elements. I want to search elements with UniqueID attribute . Eventhough i tried using following DTD its not sufficient.
<!DOCTYPE root [
<!ELEMENT root ANY>
<!ATTLIST Person UniqueID ID #REQUIRED>
]>
The Problem is UniqueID may occur in several elements attribute list.
I need to avoid a situation which i have to declare every occurances of elements that have UniqueID attribute in DTD.
Can Anyone suggest any idea for that?
Thanks
Try using LINQ to XML, no need for DTD.
// XML data
var xml = "<root><secondRoot><Person UniqueID='A112' Name='Fred'><FeMale>I am Female</FeMale></Person><Person UniqueID='A111'><Male>I am male</Male></Person> <Person SSN='A222' Name='Tom'/> <Customer id='A111'/> <Customer id='A222334444'/> <Team members='A222334444 A333445555'/> <Random/></secondRoot></root>";
var doc = XDocument.Parse(xml);
// Get all nodes that have UniqueID
var nodes =
from element in doc.Descendants()
where element.Attribute("UniqueID") != null
select element;
The nodes list will contain all nodes that have the UniqueID attribute.
I am developing asp.net mobile application. I am using the XML as a database. I am using the following part of the XML file to query the data by using the LINQ to XML.
<USER-INTERFACE-DEFINITION>
<MIMICS>
<MIMIC ID="1" NAME="Home">
<SECTIONS>
<SECTION ID ="1" NAME="System Health" CONTROL-TYPE="Button">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID ="2" NAME="Network Status" CONTROL-TYPE="Button">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID ="3" NAME="ESD Status" CONTROL-TYPE="Button">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID ="4" NAME="DWPLEM" CONTROL-TYPE="Button">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID="5" NAME="Manifolds" CONTROL-TYPE="Drowpdown">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID ="6" NAME="Wells" CONTROL-TYPE="Drowpdown">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID ="7" NAME="Alarms" CONTROL-TYPE="Button">
<DATAITEMS>
</DATAITEMS>
</SECTION>
<SECTION ID ="8" NAME="House Keeping" CONTROL-TYPE="Button">
<DATAITEMS>
</DATAITEMS>
</SECTION>
</SECTIONS>
</MIMIC>
</USER-INTERFACE-DEFINITION>
In the above XML file I want to retrive the "NAME" attribute of the SECTION node with the condition MIMIC ID="1". I dont want to modify my existing XML file. I have the server collection of node with simialr elements as the above XML file. Can you please provide me any code or link through which I can resolve the above issue ?
var xml = XElement.Parse("your xml");
var q = from m in xml.Descendants("MIMIC")
where (int)m.Attribute("ID") == 1
from s in m.Descendants("SECTION")
select (string)s.Attribute("NAME");
foreach ( var name in q ) {
Console.WriteLine(name);
}
I have tested the above in LINQPad and it does indeed produce:
System Health
Network Status
ESD Status
DWPLEM
Manifolds
Wells
Alarms
House Keeping
Perhaps something like (not LINQ, but you can use it with LINQ if you like):
var nodes = myXmlDoc.SelectNodes("/USER-INTERFACE-DEFINITION/MIMICS/MIMIC[#ID='1']/SECTION/#NAME");
foreach(var node in nodes)
{
string name = node.Value;
// do something with each name
}
(assuming myXmlDoc is created using .Load(yourXmlFileHer) and assuming USER-INTERFACE-DEFINITION is the root of the XML, otherwise, start with // instead)
Assuming your XML is held in a string called xml then:
var root = XElement.Parse(xml);
var results = root
.Descendants("MIMIC")
.Where( e => e.Attribute("ID").Value == "1" )
.SelectMany(e => e.Descendants("SECTION").Attributes("NAME" ) ) ;
I'll give it my best try but you might wan't to supply the relevant part of the XML to make it easier for us. Does the section have this condition or the name. At least I might get you started.
Let's start with this:
var name = xml.Descendants<SECTION>.Where(s => s.id == 1).GetFirstChild<NAME>();
Hoping I'm not way off, if that's the case I guess someone will suply a better answer.
Ok after seeing your XML I was some way off. Also when I think about it Descendants probably woudln't work.