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.
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 have an XML file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="publisher" type="KP.Common.Util.XamlConfigurationSection, KP.Common"/>
</configSections>
<publisher>
<p:Publisher xmlns:p="http://schemas.KP.com/xaml/common/notification">
<p:KPLogSubscriber MinimumImportance="Information" />
<p:EventLogSubscriber MinimumImportance="Warning" Source="KPTTY" Log="Application" />
<p:DatabaseMailSubscriber xmlns="http://schemas.KP.com/xaml/data/ef" MinimumImportance="Error" ProfileName = "" Recipients = "administrator#firm.com" Subject = "KPTTY Error" />
</p:Publisher>
</publisher>
</configuration>
I am trying to read the value of the key Recipients using this code:
XmlDocument config = new XmlDocument();
config.Load(configPath);
XmlNode node = config.SelectSingleNode(#"/*[local-name() = 'configuration']/*[local-name() = 'publisher']/*[local-name() = 'Publisher']/*[local-name() = 'DatabaseMailSubscriber']/#Recipients");
Console.WriteLine(node.Value);
but I get an exception (node is null). Is there something wrong with my Xpath? I am trying to ignore any namespaces that might not be present in the xml.
If it is OK to use Linq2Xml
XDocument xDoc = XDocument.Load(fname);
var recipients = xDoc.Descendants()
.First(d => d.Name.LocalName == "DatabaseMailSubscriber")
.Attribute("Recipients")
.Value;
You forgot to do local-name for "Recipients". "Recipients" attribute have empty prefix meaning its namespace is xmlns="http://schemas.KP.com/xaml/data/ef" as defined on the "DatabaseMailSubscriber" element.
I.e. if you don't care of path you can simple use "//" for "any child:
"//*[local-name() = 'DatabaseMailSubscriber']/#*[local-name() = 'Recipients]"
Note: consider actually using namespace properly... or use XDocument as suggested by L.B.
I have a simple program that would let the user add a section to a custom config file, it would have more settings than what is shown. I populate a datagridview with a list of all configurations. My problem is, the method to populate the listbox wouldn't know all the names of the sections that the user may have added, I'm trying to be dynamic. Is there an easy way to loop through these sections and get their names? Or do I have to make a Section, Collection, and Elements in order to to this?
Thanks.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="Jason" type="SQLQueryOutput.SQLQueryOutputConfigSection, SQLQueryOutput, Version=1.0.0.0, Culture=neutral, PublicKeyToken=760d257b40400289" />
<section name="Steve" type="SQLQueryOutput.SQLQueryOutputConfigSection, SQLQueryOutput, Version=1.0.0.0, Culture=neutral, PublicKeyToken=760d257b40400289" />
</configSections>
<Jason OutputFilePath="C:\temp\jason.txt" />
<Steve OutputFilePath="C:\temp\steve.txt" />
</configuration>
How about using Linq To Xml to parse your config file. For example,
var xDoc = XDocument.Load(configFile);
var sections = xDoc.XPathSelectElements("//configSections/section")
.Select(x=>x.Attributes().ToDictionary(a=>a.Name,a=>a.Value))
.ToList();
var name = sections[0]["name"];
or
var outputFilePaths = xDoc.Root.Elements()
.Where(d => d.Name.LocalName != "configSections")
.ToDictionary(e => e.Name.LocalName, e => e.Attribute("OutputFilePath").Value);
Actually your configSections element can contain sectionGroup elements also. With Linq to Xml:
XDocument xdoc = XDocument.Load(config_file_path);
var names = xdoc.Root.Element("configSections")
.Descendants("section") // selects also sectionGroup/section
.Select(s => (string)s.Attribute("name"));
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.
I am trying to extract information from an XML file into an object using LINQ to XML. Although I can return the document and section Id attributes I cannot get access to the Items for each section element, it returns an IEnumerable of all the items in the document. I know this is correct as I’m calling Descendants but am struggling to get it to return only the child items of each section element. Can anybody help?
XML Document
<root>
<document id="1">
<section id="1.1">
<item id="1.1.1"></item>
<item id="1.1.2"></item>
<item id="1.1.3"></item>
</section>
<section id="1.2">
<item id="1.2.1"></item>
<item id="1.2.2"></item>
</section>
</document>
</root>
LINQ Query
XElement documentRoot = XElement.Load("document.xml");
var documents = (from docs in documentRoot.Descendants("document")
select new
{
Id = (string) docs.Attribute("id"),
Sections = docs.Elements("section"),
Items = docs.Elements("section").Elements("item")
}).ToList();
foreach(var doc in documents)
{
foreach(var section in doc.Sections)
{
Console.WriteLine("SectionId: " + section.Attribute("Id"));
foreach(var item in doc.Items)
{
Console.WriteLine("ItemId: " + section.Attribute("Id"));
}
}
}
You got some small typos, on attribute Id and at item loop. But if you're trying to get all section items into that items collection, you're wrong at design level, as Items should be a Section property, not Document (so you'll need to query your XML twice).
Or, you can to do something like:
var documents =
(from docs in documentRoot.Descendants("document")
select new
{
Id = (string) docs.Attribute("id"),
Sections = docs.Elements("section")
}).ToList();
foreach (var doc in documents)
{
foreach (var section in doc.Sections)
{
Console.WriteLine("SectionId: " + section.Attribute("id"));
foreach (var item in section.Elements("item"))
{
Console.WriteLine("ItemId: " + item.Attribute("id"));
}
}
}
Output:
SectionId: id="1.1"
ItemId: id="1.1.1"
ItemId: id="1.1.2"
ItemId: id="1.1.3"
SectionId: id="1.2"
ItemId: id="1.2.1"
ItemId: id="1.2.2"
Do you want a flat structure ?!?! (from LinqPad)
XElement documentRoot = XElement.Parse (
#"<root>
<document id='1'>
<section id='1.1'>
<item id='1.1.1'></item>
<item id='1.1.2'></item>
<item id='1.1.3'></item>
</section>
<section id='1.2'>
<item id='1.2.1'></item>
<item id='1.2.2'></item>
</section>
</document>
</root>
");
var documents = (from docs in documentRoot.Descendants("section")
select new
{
SectionId = (string) docs.Attribute("id"),
Items = docs.Elements("item")
});
documents.Dump();
This gives 2 SectionId items that containes XElements with related items.