I have a xml like this:
<?xml version="1.0" encoding="utf-8"?>
<assessment xmlns="http://xml.thinkcentral.com/pub/xml/hsp/assessment" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:tia="http://xml.thinkcentral.com/pub/xml/hsp/tia" xmlns:tibase="http://xml.thinkcentral.com/pub/xml/hsp/tibase" xsi:schemaLocation="http://xml.thinkcentral.com/pub/xml/hsp/assessment http://xml.thinkcentral.com/pub/xml1_2_6/hsp_assessment.xsd" isbn="9780547660455" buid="NA12_AG_G01CH01A" title="Chapter 1 Test Form A" num_questions="24" num_sections="1" type="Basal" intervenable="true" duration="P5Y" pausable="false" scramble="false">
<test_section id="1" name="Chapter 1 Test Form A" index="1">
<aaa testitem_id="NA12_AG_G01CH01A_01" template="hsp_testitem_mc1.xslt" id="1" bankable="true">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody></tia:textBody>
</tia:tiDirectionLine>
<tia:address>Richtextbox Data</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
<aaa testitem_id="NA12_AG_G01CH01A_02" template="hsp_testitem_mc1.xslt" id="2" bankable="true">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody></tia:textBody>
</tia:tiDirectionLine>
<tia:address>Richtextbox Data</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
</test_section>
</assessment>
I have to insert the the data according to the id of the aaa element.
<aaa testitem_id="NA12_AG_G01CH01A_01" template="hsp_testitem_mc1.xslt" id="1" bankable="true">
<aaa testitem_id="NA12_AG_G01CH01A_02" template="hsp_testitem_mc1.xslt" id="2"bankable="true">
if id="1" then data of ritchtextbox will be insert into tia:address node.
i am using the following code.
private void button2_Click(object sender, EventArgs e)
{
XDocument doc = XDocument.Load(#"d:\file.xml");
XNamespace ns = XNamespace.Get("http://tia.com");
var result= (from ele in doc.Descendants("aaa")
where ((string)ele.Attribute("id")) == "1"
select ele.Element(ns+"address")).FirstOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(#"d:\file.xml");
}
MessageBox.Show("done");
}
its not working. how i do that?
First of al, the XML markup you have posted is not valid. I think the easiest way to read/write an XML document is Linq-XML. You have to import System.Xml.Linq namespace to use XDocument class and its method. Take a look at MSDN article.
XDocument doc = XDocument.Load(#"c:\file.xml");
var result = (from ele in doc.Descendants("aaa")
where ((string)ele.Attribute("id")) == "1"
select ele.Element("address")).FirstOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(#"c:\file.xml");
}
XML document should be:
<?xml version="1.0" encoding="utf-8"?>
<root>
<aaa id="1">
<address>Hello World</address>
</aaa>
<aaa id="2">
<address>
write text of ritchtextbox here</address>
</aaa>
</root>
EDIT:
In OP, XML markup has some issues and I've fixes the markup (added namespace).
<?xml version="1.0" encoding="utf-8"?>
<aaa testitem_id="chapter1" template="hsp_testitem_mc1.xslt" id="1" bankable="true" xmlns:tia="http://tia.com">
<tia:multipleChoiceTestItem total-points="1" questionType="Multiple Choice" sample="false" version_label="1.0">
<tia:directions>
<tia:tiDirectionLine>
<tia:textBody />
</tia:tiDirectionLine>
<tia:address>I have to edited here.(Richtextbox data)</tia:address>
</tia:directions>
</tia:multipleChoiceTestItem>
</aaa>
Code to find <tia:address> and replace its value.
XDocument doc = XDocument.Load(file);
XNamespace ns = XNamespace.Get("http://tia.com");
var result = (from ele in doc.Descendants(ns + "address")
select ele).SingleOrDefault();
if (result != null)
{
result.Value = richTextBox1.Text;
doc.Save(file);
}
EDIT : After changes made by OP in opening post.
XDocument doc = XDocument.Load(file);
//Change the namespace
XNamespace ns = XNamespace.Get("http://xml.thinkcentral.com/pub/xml/hsp/tia");
var result = (
from ele in doc.Descendants(ns + "multipleChoiceTestItem")
where ele.Parent.Attribute("id").Value == "1"
select
ele.Descendants(ns+"address").FirstOrDefault()
).FirstOrDefault();
if (result != null)
{
result.Value = "World";
doc.Save(file);
}
Related
I am trying to modify the following XML doc (MRE) using Linq to XML:
Move the school name and address one step higher or at the level of its parent—school element.
At the same time, change its name to <School_Name> and <School_Address>.
ORIGINAL
<?xml version="1.0" encoding="utf-8"?>
<GreatGrandParent>
<GrandParent>
<Parent>
<Child>
<Name>John</Name>
<Address>California</Address>
<Sex>Male</Sex>
<Age>18</Age>
<School>
<Name>Cool School</Name>
<Address>California</Address>
</School>
</Child>
<Child>
<Name>Mary</Name>
<Address>New Orleans</Address>
<Sex>Female</Sex>
<Age>16</Age>
<School>
<Name>Pretty School</Name>
<Address>New Orleans</Address>
</School>
</Child>
<Parent>
<GrandParent>
<GreatGrandParent>
TARGET MODIFICATION
<?xml version="1.0" encoding="utf-8"?>
<GreatGrandParent>
<GrandParent>
<Parent>
<Child>
<Name>John</Name>
<Address>California</Address>
<Sex>Male/Sex>
<Age>18</Age>
<School_Name>Cool School</School_Name>
<School_Address>California</School_Address>
</Child>
<Child>
<Name>Mary</Name>
<Address>New Orleans</Address>
<Sex>Female/Sex>
<Age>16</Age>
<School_Name>Pretty School</School_Name>
<School_Address>New Orleans</School_Address>
</Child>
<Parent>
<GrandParent>
<GreatGrandParent>
HERE'S WHAT I HAVE DONE SO FAR:
XDocument doc = XDocument.Load(#"D:\Xml\Childs Profile.xml");
XElement root = doc.XPathSelectElement("//Parent");
IEnumerable<XElement> rootlists = root.Descendants("Child").ToList();
foreach (var rootlist in rootlists)
{
XElement lists = root.Element("Child");
XElement name = root.Element("Child").Element("School").Element("Name");
XElement address = root.Element("Child").Element("School").Element("Address");
list.AddFirst(name);
list.AddFirst(address);
XElement school = root.Element("Child").Element("School");
school.Remove();
}
doc.Save(#"D:\Xml\Childs Profile.xml");
ISSUES: The foreach above does not move to next child.
PENDING: Change the XName to <School_Name> and <School_Address> either before or after moving.
You can try this:
XDocument doc = XDocument.Load(#"the.xml");
var child = doc.Descendants("Child");
var school = child.Elements("School");
string name = $"{school.First().Name}_{school.Elements("Name").First().Name}";
string address = $"{school.First().Name}_{school.Elements("Address").First().Name}";
foreach (var s in school)
{
s.Parent.Add(new XElement(name, s.Element("Name").Value));
s.Parent.Add(new XElement(address, s.Element("Address").Value));
}
school.Remove();
doc.Save(#"out.xml");
I am using WebRequest and WebReponse classes to get a response from a web api. The response I get is an xml of the following format
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<A></A>
<B></B>
<C></C>
<D>
<E NAME="aaa" EMAIL="a#a.com"/>
<E NAME="bbb" EMAIL="b#b.com"/>
</D>
</ROOT>
I want to get all the E elements as a List<E> or something.
Can some one guide me on this pls.
if you want to avoid serialization, as you only want a very specific part of the xml, you can do this with one LINQ statement:
var items = XDocument.Parse(xml)
.Descendants("E")
.Select(e => new
{
Name = e.Attribute("NAME").Value,
Email = e.Attribute("EMAIL").Value
})
.ToList();
Working example:
var doc = XDocument.Parse(#"<?xml version='1.0' encoding='UTF-8'?>
<ROOT>
<A></A>
<B></B>
<C></C>
<D>
<E NAME='aaa' EMAIL='a#a.com'/>
<E NAME='bbb' EMAIL='b#b.com'/>
</D>
</ROOT>");
var elements = from el in doc.Elements()
from el2 in el.Elements()
from el3 in el2.Elements()
where el3.Name == "E"
select el3;
foreach (var e in elements)
{
Console.WriteLine(e);
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Report SYSTEM "https://abc.mycompany.com/abc/processingreports/processeddtd/abcd_1_8.dtd">
<Report Name="Daily TRANSACTIONS"
Version="1.8"
xmlns="https://abc.mycompany.com/abc/processingreports/processeddtd/abcd_1_8.dtd"
OrgID="ABC_PQR" StartDate="2011-03-10T00:00:00+00:00" EndDate="2011-03-11T00:00:00+00:00">
<Requests>
<Request ID="2"
Date="2011-03-10T00:21:14+00:00"
OrderNumber="1">
<BillTo>
<FirstName />
</BillTo>
<LineItems>
<LineItem Number="0">
<Quantity />
</LineItem>
</LineItems>
</Request>
<Request ID="2"
Date="2011-03-10T00:21:14+00:00"
OrderNumber="1">
TransactionNumber="389958330911111">
<BillTo>
<FirstName>A</FirstName>
</BillTo>
<LineItems>
<LineItem Number="0">
<Quantity>1</Quantity>
</LineItem>
</LineItems>
<UniqueData>
<UniqueNumber>11111111111111111111111111111</UniqueNumber>
</UniqueData></Request></Requests></Report>
In above XML file using Linq i just
want to extract OrderNumber and
UniqueNumber
OrderNumber="1"
11111111111111111111111111111
Any ideas, suggestions to extract these details?
I can select elements from above xml file but UniqueNumber is not associated with OrderNumber
I am looking for something below (ignore lines where UniqueNumber is not present)
OrderNumber - assosicated UniqueNumber
Update
In "requiredElements" i am expecting two coulmns OrderNumber and UniqueNumber and holding associated values with each other as 1 and 11111 and so one
#region FileOpen with UTF8 Encoding
TextReader sr = new StreamReader(cFileName, Encoding.UTF8);
XDocument reportfile = XDocument.Load(sr, LoadOptions.SetBaseUri);
XElement xd = XElement.Parse(reportfile.ToString());
sr.Close();
#endregion
XNamespace ns = xd.Attribute("xmlns").Value;
var requiredElements = (from resultquery in reportfile.Descendants()
select new
{
OrderNumber = resultquery.Attribute("OrderNumber"),
UniqueNumber= (string)resultquery.Element(AddNameSpace(ns, "UniqueNumber")),
}
);
Here is some sample:
XDocument doc = XDocument.Load(#"file.xml");
XNamespace df = doc.Root.Name.Namespace;
var results = from request in doc.Descendants(df + "Request")
where request.Elements(df + "UniqueData").Elements(df + "UniqueNumber").Any()
select new
{
ordNumber = (int)request.Attribute("OrderNumber"),
uniqueNumber = (decimal)request.Element(df + "UniqueData").Element(df + "UniqueNumber")
};
foreach (var result in results)
{
Console.WriteLine("{0}-{1}", result.ordNumber, result.uniqueNumber);
}
I have an xml doc similar to this:
<Root>
<MainItem ID="1">
<SubItem></SubItem>
<SubItem></SubItem>
<SubItem></SubItem>
</MainItem>
<MainItem ID="2">
<SubItem></SubItem>
<SubItem></SubItem>
<SubItem></SubItem>
</MainItem>
...
</Root>
I want to return the whole of the MainItem element based on the value of attribute ID.
So effectively if Attribute ID is equal to 2, then give me that MainItem element back.
I can't work out how to do this with LINQ.
There seems to be a load of information on google, but I just can't quite seem to find what I'm looking for.
Little help ?
TIA
:-)
It could be something like this:
XDocument doc = XDocument.Load("myxmlfile.xml");
XElement mainElement = doc.Element("Root")
.Elements("MainItem")
.First(e => (int)e.Attribute("ID") == 2);
// additional work
How about this:
// load your XML
XDocument doc = XDocument.Load(#"D:\linq.xml");
// find element which has a ID=2 value
XElement mainItem = doc.Descendants("MainItem")
.Where(mi => mi.Attribute("ID").Value == "2")
.FirstOrDefault();
if(mainItem != null)
{
// do whatever you need to do
}
Marc
I changed your XML slightly to have values:
<?xml version="1.0"?>
<Root>
<MainItem ID="1">
<SubItem>value 1</SubItem>
<SubItem>val 2</SubItem>
<SubItem></SubItem>
</MainItem>
<MainItem ID="2">
<SubItem></SubItem>
<SubItem></SubItem>
<SubItem></SubItem>
</MainItem>
</Root>
And with this LINQ:
XDocument xmlDoc = XDocument.Load(#"C:\test.xml");
var result = from mainitem in xmlDoc.Descendants("MainItem")
where mainitem.Attribute("ID").Value == "1"
select mainitem;
foreach (var subitem in result.First().Descendants())
{
Console.WriteLine(subitem.Value);
}
Console.Read();
From here: How to: Filter on an Attribute (XPath-LINQ to XML)
// LINQ to XML query
IEnumerable<XElement> list1 =
from el in items.Descendants("MainItem")
where (string)el.Attribute("ID") == "2"
select el;
// XPath expression
IEnumerable<XElement> list2 = items.XPathSelectElements(".//MainItem[#ID='2']");
I have the following XML. How to read the root node attribite value and it's decendents using LINQ? I am trying to read "dId" and "dTime" from root node, "id" from Customer element and Order number.
<?xml version="1.0" encoding="utf-8" ?>
<Customers dId="wqwx" dTime="10-9-09 11:23">
<Customer id="1">
<Orders>
<Order number="22" status="ok">
</Orders>
</Customer>
</Customers>
I tried the following code but it doesn't work.
XDocument doc= XDocument.Load(#"C:\Customers.xml");
var q = from c in doc.Descendants("Customers")
select new
{
dID = c.Attribute("dId"),
dTime = c.Attribute("dTime");
}
first, fix your xml (<Order .... />)
then, your linq should look like this....
// .Elements(...) selects all elements of type "Customer"
var q = from c in xDoc.Elements("Customers")
select new
{
dID = c.Attribute("dId"),
dTime = c.Attribute("dTime")
};
you should dl LinqPad... it lets you do Linq queries on the fly, even agains SQL databases. Then, once you get the results you want, copy and past your linq into your source code.
You have to end the order tag with: />
xDoc.Descendants("Customers") should work as well as xDoc.Elements("Customers").
Chris, is there a specific advantage to using .Elements?
You can't use LINQ to access the root tag.
The code below does what you want (I included a well formed xml file as well):
using System;
using System.Linq;
using System.Xml.Linq;
namespace ReadXmlSpike
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Reading file...");
XDocument doc = XDocument.Load("Customers.xml");
var customers =
new
{
DID = (string) doc.Element("Customers").Attribute("did"),
DTime = (DateTime) doc.Element("Customers").Attribute("dTime"),
Customers = from customerxml in doc.Descendants("Customer")
select
new
{
ID = (string)customerxml.Attribute("id"),
Orders = from orderxml in customerxml.Descendants("Order")
select
new
{
Number =(string) orderxml.Attribute("number")
}
}
};
Console.WriteLine("Customersfile with id: {0} and time {1}",customers.DID,customers.DTime);
foreach (var customer in customers.Customers)
{
Console.WriteLine("Customer with id {0} has the following orders:",customer.ID);
foreach (var order in customer.Orders)
{
Console.WriteLine("Order with number {0}",order.Number);
}
}
Console.ReadLine();
}
}
}
and the xml file:
<?xml version="1.0" encoding="utf-8" ?>
<Customers did="www" dTime="10-09-09 11:23">
<Customer id="1">
<Orders>
<Order number="22" status="ok"/>
<Order number="23" status="bad"/>
</Orders>
</Customer>
<Customer id="2">
<Orders>
<Order number="24" status="ok"/>
<Order number="25" status="bad"/>
</Orders>
</Customer>
</Customers>
XDocument d = XDocument.Parse(#"<?xml version='1.0' encoding='utf-8' ?>
<Customers dId='wqwx' dTime='10-9-09 11:23'>
<Customer id='1'>
<Orders>
<Order number='22' status='ok'/>
</Orders>
</Customer>
</Customers>");
var cu = d.Root.Elements().Where(n => n.Name == "Customer");
var c = from cc in cu
select new
{
dId = cc.Document.Root.Attribute("dId").Value,
dTime = cc.Document.Root.Attribute("dTime").Value,
ID = cc.Attribute("id").Value,
number = cc.Element("Orders").Element("Order").Attribute("number").Value
};
foreach (var v in c)
{
Console.WriteLine("dId \t\t= {0}", v.dId);
Console.WriteLine("dTime \t\t= {0}", v.dTime);
Console.WriteLine("CustomerID \t= {0}", v.ID);
Console.WriteLine("OrderCount \t= {0}", v.number);
}
Console Output:
================================
dId = wqwx
dTime = 10-9-09 11:23
CustomerID = 1
OrderCount = 22
请按任意键继续. . .
It does not work the way you wrote it: while printing the above code would complain about anonymous type.
However, with this simple modified version d.Document.Root.Attribute("dId").Value; you can assign it to a string.