C# - How to split,replace the content of xml file? - c#

I have a xml file:
<xml ?iwes sf>
<product>
<name> Computer </name>
<details>a product of Dell</details>
<sender> sender no name</sender>
</product>
</xml>
i want split to:
<xml ?iwes sf>, ,<product>, ,<name>,Computer,</name>,..., ,</xml>
Then i translate text content (Computer,a product of Dell, sender no name) to Korean Language.
Finally, i want join
<xml ?iwes sf>, ,<product>, ,<name>,Computer,</name>,..., ,</xml>
with result translated:
<xml ?iwes sf>
<product>
<name> 컴퓨터</name>
<details>Dell의 제품 </details>
<sender> 아니오 유명한 송신기 </sender>
</product>
</xml>
i used Regex:
string[] gettag = Regex.Split(inputText.Text, "(<.*?>)|(.+?(?=<|$))");
but it's wrong, it cann't do what i want, i cann't join xml tag to location before, cause it cann't get "\t"!
What should i do??
My English level is'ot good. I hope everyone can understand what i said and help me!
Thanks!

y not some lambda expression ?
you can try this.
IEnumerable<XElement> xx = xdoc.Root.Descendants().Elements().Where(c => { if (c.Name == "name") { c.Value = "Dell"; } else if (c.Name == "details") { c.Value = "Dell Detial"; } return true; }).Select(c => c);
// Loop.
string x = string.Empty;
foreach (XElement x1 in xx)
{
x += x1.ToString();
}
Console.WriteLine(x.ToString());

Related

Formatting an elements text using descendants of XElement

Im wondering how to select a specific element from the heirarchy so that I can format its text.
In the example below I would like to format the specific element to remove the time portion of the date, but I am also looking for a way to format any of the elements for example to add a currency symbol to the text between each price tag.
My example
<orders>
<order>
<type> tools </type> //I would like the ability to select this element
<text> screwdriver </text>
<id> 100981 </id>
<price> 5.00 </price>
<date> 01/01/15 12:51:36 </date>
</order>
<order>
<type> uniform </type>
<text> boots </text>
<id> 100546 </id>
<price> 25.00 </price>
<date> 12/01/15 15:30:41 </date>
</order>
</orders>
What I have so far
foreach (XElement element in doc.Descendants())
{
var nodes = element.Nodes().Where(p => p.NodeType == XmlNodeType.Text);
foreach (XText node in nodes)
{
node.Value = FirstLetterToUpper( node.Value );// set the first letter of each output to be uppercase
}
}
What I have tried
foreach (XElement element in doc.Descendants())
{
var nodes = element.Nodes().Where(p => p.NodeType == XmlNodeType.Text);
if( element.Descendants() == element.Element("date"))
{
element.Value = Convert.ToDateTime(element.Value).ToShortDateString();
}
foreach (XText node in nodes)
{
node.Value = FirstLetterToUpper( node.Value );
}
}
I have some XML experience but have never worked with XElement before.
I've been searching SO for a while now but cant find what Im looking for. The answers below are some of the suggested answers from typing this question but they dont provide a solution as the XML elements are generated dynamically in a loop.
XElement node with text node has its formatting ignored
string.Format in XElement not formatting
Any help with this would be great as I have not attempted this before. Thanks.
You can get the text node's parent using Parent property and check it's name:
foreach (XText node in doc.DescendantNodes()
.Where(x => NodeType == XmlNodeType.Text))
{
if(node.Parent.Name == "date") { ... }
if(node.Parent.Name == "price") { ... }
}
BTW, don't forget the save the document using XDocument.Save method after you made the changes.
I usually create one class to represent the xml and send yo the instance of object with correct type. for Example convert.ToDecimal(node.innerText)

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.

Insert the data of richtextbox into existing xml in c# linq

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);
}

Search XML doc with LINQ

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']");

how to get root node attribute value using linq

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.

Categories

Resources