C# XML Select Multiple Nodes - c#

I am trying to modify a website that was built by some other web developers.
The part in question, reads an XML data file and pulls back data to display on a Google Map.
They have a line of code;
string path = Server.MapPath(OutageXmlVirtualPath); //path to XML file
OutageData outages = XMLUtil.Deserialize<OutageData>(path);
Outage outage = outages.Outages.FirstOrDefault(o => o.PostCodes.Any(p => FoundOutagePostcode(p)) && !o.Planned);
That pulls the First record in the XML that matches a postcode the user has entered into a textbox. (lastOrDefault works also)
The issue with this however, is that the postcode they enter might appear more than once. In another node in the XML. So what I want to do is pull back all of the records in the XML that match. Not just the first. I can see that there is 'All' and 'SelectMany' methods, but dont know how to implement these into my code.
I would consider myself a complete novice in this area.
If anyone is able to lend any help that would be greatly appreciated.
Kind regards,
Chris
XML sample
<?xml version="1.0" encoding="utf-16"?>
<OutageData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TimeStamp>2013-12-16T06:38:00.1706983+00:00</TimeStamp>
<Outages>
<Outage>
<Region>South West</Region>
<IncidentID>INCD-83651-m</IncidentID>
<ConfirmedOff>1</ConfirmedOff>
<PredictedOff>0</PredictedOff>
<Restored>0</Restored>
<Status>In Progress</Status>
<Planned>false</Planned>
<StartTime>2013-12-14T18:03:00</StartTime>
<ETR>2013-12-16T12:00:00</ETR>
<Voltage>LV</Voltage>
<PostCodes>
<string>PL1 4RL</string>
<string>PL2 1AF</string>
<string>PL2 1AG</string>
<string>PL2 1AH</string>
</PostCodes>
<Sensitive>1</Sensitive>
</Outage>
<Outage>
<Region>West Midlands</Region>
<IncidentID>INCD-12499-I</IncidentID>
<ConfirmedOff>0</ConfirmedOff>
<PredictedOff>0</PredictedOff>
<Restored>0</Restored>
<Status>In Progress</Status>
<Planned>true</Planned>
<StartTime>2013-12-13T10:00:00</StartTime>
<ETR xsi:nil="true" />
<Voltage>HV</Voltage>
<PostCodes>
<string>SY7 9AX</string>
<string>SY7 9AY</string>
<string>SY7 9AZ</string>
<string>SY7 9BE</string>
</PostCodes>
<Sensitive>0</Sensitive>
</Outage>
</Outages>
</OutageData>

just try to use Where
var outagesFound = outages.Outages.Where(o => o.PostCodes.Any(p => FoundOutagePostcode(p)) && !o.Planned);
and then you can iterate through the outagesfound list using the foreach loop

Related

How to take data from multiple nodes in a xml file use them in different text file using c#?

I have a sample xml file which is like below
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD with OASIS Tables v1.0 20120330//EN" "JATS-journalpublishing-oasis-article1.dtd">
<article article-type="proceedings" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:oasis="http://www.niso.org/standards/z39-96/ns/oasis-exchange/table">
<front>
<journal-meta>
<journal-id journal-id-type="publisher-id"/>
<journal-title-group>
<journal-title>Eleventh International Conference on Correlation Optics</journal-title>
</journal-title-group>
<issn pub-type="epub">0277-786X</issn>
<publisher>
<publisher-name>SPIE</publisher-name>
</publisher>
</journal-meta>
<article-meta>
<article-id pub-id-type="doi">10.236/12.205210</article-id>
<title-group>
<article-title>So you think you can dance?</article-title>
</title-group>
<contrib-group>
<contrib contrib-type="author">
<name>
<surname>Cena</surname>
<given-names>John</given-names>
</name>
<xref ref-type="aff" rid="a1"><sup>a</sup></xref>
</contrib>
<contrib contrib-type="author" corresp="yes">
<name>
<surname>Pal</surname>
<given-names>G.S.</given-names>
</name>
<xref ref-type="aff" rid="a2"><sup>b</sup></xref>
</contrib>
<aff id="a1"><label><sup>a</sup></label>CNRS, France</aff>
<aff id="a2"><label><sup>b</sup></label>MIT, USA</aff>
</contrib-group>
</article-meta>
</front>
<body>
<sec id="S1">
<label>1.</label>
<p>Today is your lucky day</p>
</sec>
<sec id="S2">
<label>2.</label>
<p>Today is not so lucky</p>
</sec>
</body>
</article>
I'm tying to get contents of some of the nodes(first node found) and put them in variables and then use regex replace using them in a different TXT file in efficient manner.
I'm trying something like
XDocument doc=XDocument.Load(#"D:\MyFiles\1235-12-3053\230\124\124.xml",LoadOptions.PreserveWhitespace);
var s=from a in doc.Descendants("surname")
select a.First();
var l=from x in doc.Descendants("label")
select x.First();
... so on
File.WriteAllText(#"C:\Desktop\text.txt", Regex.Replace(File.ReadAllText(#"C:\Desktop\text.txt"), #"<a>[^<]+</a>", #"<a>s</a>"));
File.WriteAllText(#"C:\Desktop\text.txt", Regex.Replace(File.ReadAllText(#"C:\Desktop\text.txt"), #"<b>[^<]+</b>", #"<b>l</b>"));
... so on
But First() method is giving an error, and also using WriteAllText many times, is that a good practice? Can I do multiple replaces in one go?
Instead of loading and saving the file to the hard drive multiple times, you should consider loading the text to a variable (string).
When i memory you can use regex to search and replace for multiple different patterns as you wish, and when completely done save the file.
Try something like this
XDocument doc=XDocument.Load(file,LoadOptions.PreserveWhitespace);
var s=(from a in doc.Descendants("surname")
select a).First().Value;
var l=(from x in doc.Descendants("label")
select x).First().Value;
string text = File.ReadAllText(file);
text = Regex.Replace(text, #"<a>[^<]+</a>", #"<a>"+s+#"</a>");
text = Regex.Replace(text, #"<b>[^<]+</b>", #"<b>"+l+#"</b>");
File.WriteAllText(file, text);
This should do if I understand correctly what you wanted from this program.
There is also a method called UpdateText I believe, to do the updating of the file but I'm not that familiar with it...maybe someone else can help you on that method.

How to search through XML to find bad nodes

I have a large XML file (68Mb), I am using SQL Server Business Intelligence Studio 2008 to extract the XML data into a database. There is an error in the XML file some where that prevents it from executing. Possibly a missing tag or something like that. The file is so large I cant manually sort through it looking for the error.
Below is a sample of the the XML schema used.
How can I use XPath to sort through the XML in VS 2012 using C#?
An example would be great!
-<PhoneNumberList>
<PhoneNumber value="1234567890" type="Phone"/>
</PhoneNumberList>
-<YearsOfServiceList>
<YearsOfService experienceInMonths="24" description="SuperAdmin" objectCode="049"/>
</YearsOfServiceList>
</Person>
-<Person dob="1960-01-09T00:00:00" lastName="Smith" middleName="Will" firstName="John" id="9999-9999-9999">
-<SiteList>
-<Site id="2014" siteLongName="HA" siteCode="1255" systemCode="999">
-<StaffPositionList>
<StaffPosition id="73" staffPosition="Administrator"/>
</StaffPositionList>
</Site>
</SiteList>
-<ProgramList>
<Program id="1234" siteLongName="ABC" siteCode="0000" systemCode="205"/>
<Program id="5678" siteLongName="DEF" siteCode="0000" systemCode="357"/>
</ProgramList>
-<TypeList>
<Type Description="Leader" certificateType="D"/>
<Type Description="Professional" certificateType="P"/>
</TypeList>
-<EmailList>
<Email value="jsmith#somesite.com" type="Email"/>
</EmailList>
-<PhoneNumberList>
<PhoneNumber value="1234567890" type="Phone"/>
</PhoneNumberList>
-<YearsOfServiceList>
<YearsOfService experienceInMonths="24" description="SuperAdmin" objectCode="049"/>
</YearsOfServiceList>
</Person>
</PersonList>
</GetPersonDetail>
If you want to do it in code then create an XSD file describing a valid format for the data, embed it as a resource in your app and then use code like this
var errors = new List<string>();
var schemaSet = new XmlSchemaSet();
schemaSet.Add("", XmlReader.Create(new StringReader(Properties.Resources.NameOfXSDResource)));
document.Validate(schemaSet, (sender, args) =>
{
errors.Add(args.Message);
}
);
This will give you a list of validation errors.
You don't need to search "by hand" if you use a competent text editor. NotePad++'s XML plugin, for instance, can determine if your XML as a whole is well-formed or valid, and both instances will provide separate error messages.
If you don't have a schema and the file is well-formed, you can use the CLR's System.XML namespace to read in the document and then iterate through its nodes using LINQ-to-XML, which would allow you to very finely control which nodes go where. With LINQ, you could either create a new XML file with only the valid entries, procedurally correct the invalid entries as you determine where they are, or even just write to your SQL server database directly.
Your troubleshooting process should be something as follows:
Is the XML well-formed? I..e, does it comport to the fundamental rules of XML?
Is the XML valid? I.e., does it have the elements and attributes you expect?
Is your import query accurate?
For things like this I usually have luck checking and fixing the data in Notepad++. Install the XmlTools plugin and that has a menu for checking the xml syntax and tags.
Also, those dashes will give you problems, it's best to save out the xml file directly without copying by hand.
A 68MB XML file is no problem for XML editors such as XMLBlueprint 64-bit (http://www.xmlblueprint.com/) or Stylus Studio (http://www.stylusstudio.com/). Just check the well-formedness of your xml file (F7 in XMLBlueprint) and the editor will display the errors.

How to use xml with c# form application To get text for Lables Based on user Input from xml file

i'm working on An win form application in c#
i wants to add a functionality to my application by which i can change the lable.text on user input basis
i wants to use an xml file so i can set some labels as predefined values that can be changes any time without recompiling application
or changing language of my application
i have an xml file that i wants to use in my form application
<?xml version="1.0" encoding="utf-8" ?>
<product>
<product_id>1</product_id>
<product_name>Product 1</product_name>
<product_price>1000</product_price>
</product>
<product>
<product_id>2</product_id>
<product_name>Product 2</product_name>
<product_price>2000</product_price>
</product>
<product>
<product_id>3</product_id>
<product_name>Product 3</product_name>
<product_price>3000</product_price>
</product>
<product>
<product_id>4</product_id>
<product_name>Product 4</product_name>
<product_price>4000</product_price>
</product>
in my application i have some text for textbox1,textbox2 And textbox3 And Lables As
Lable1,Lable2,Lable3
on text change in textbox1 I wants to change the value of lable1.text According to id
for example if user enters 1 in textbox1 then lable text should be changed to product 1
As beginner in c# and programming don't know how to get this working....
You can parse xml with Linq to Xml. On text changed event do the following:
int id;
if (!Int32.TryParse(textbox1.Text, out id))
return; // do nothing if not integer entered
XDocument xdoc = XDocument.Load(path_to_xml_file);
var product = xdoc.Descendants("product")
.FirstOrDefault(p => (int)p.Element("product_id") == id);
lable1.Text = (product == null) ? "" : (string)product.Element("product_name");
BTW when ask question, always provide code which you already have, to show us where you stuck. Also as I commented under question your xml is invalid, because it have several root elements. Wrap all your product elements into some root, like <products>.
Consider dividing your problem in reading and writing XML in C# and look for each answer, also for setting you can use the Settings.Settings file and select User or Application if you want the setting to change or not.
Build XML
Read XML XPath
Ream XML XmlReader, single pass
Settings file

Linq to XML - how do I get this element value

Fairly simple one, but my knowledge is limited in this area. I'm using the following c# code to access the value of elements within my SGML and XML documents.
It's working fine when there is only one element with the given name in the document, but as soon as there are more than one element with the same name it throws an exception, obviously!
I need to use xpath or some other way of specifying the location of the element i'm trying to get the value of.
XDocument doc = XDocument.Load(sgmlReader);
string system = doc.Descendants("chapnum").Single().Value;
return system;
This works fine, if there is only one "chapnum" in the doc, but i need to specifically get the value of "chapnum" at the following nested location "dmaddres/chapnum".
How please?
Here is a sample of the xml doc. I'm trying to get the value of the "chapnum" element nested in the "dmaddress" element.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dmodule []>
<dmodule xmlns:dc="http://www.purl.org/dc/elements/1.1/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.s1000d.org/S1000D_2-3-1/xml_schema_flat/descript.xsd">
<idstatus>
<dmaddres>
<dmc><avee><modelic>xx</modelic><sdc>A</sdc><chapnum>29</chapnum>
<section>1</section><subsect>3</subsect><subject>54</subject><discode
>00</discode><discodev>AAA</discodev><incode>042</incode><incodev
>A</incodev><itemloc>D</itemloc></avee></dmc>
<dmtitle><techname>Switch</techname><infoname>Description of function</infoname>
</dmtitle>
<issno inwork="00" issno="001" type="new"/>
<issdate day="20" month="07" year="2012"/>
<language language="sx"/></dmaddres>
<status>
<security class="01"/><datarest><instruct><distrib>-</distrib><expcont
>Obey the national regulations for export control.</expcont></instruct>
<inform><copyright><para><refdm><avee><modelic>xx</modelic><sdc>A</sdc>
<chapnum>29</chapnum><section>1</section><subsect>3</subsect><subject
>54</subject><discode>00</discode><discodev>ZZZ</discodev><incode
>021</incode><incodev>Z</incodev><itemloc>D</itemloc></avee></refdm
></para></copyright><datacond>BREXREF=AJ-A-00-00-00-05ZZZ-022Z-D VERSUB=CDIM-V6</datacond>
</inform></datarest>
<rpc>xxxxx</rpc>
<orig>xxxxx</orig>
<applic>
<type>-</type>
<model model="xxxxx"><mfc>xxxxx</mfc><pnr>xxxxxxx</pnr></model>
</applic>
<brexref><refdm><avee><modelic>xx</modelic><sdc>A</sdc><chapnum>00</chapnum>
<section>0</section><subsect>0</subsect><subject>00</subject><discode
>05</discode><discodev>ZZZ</discodev><incode>022</incode><incodev
>Z</incodev><itemloc>D</itemloc></avee></refdm></brexref>
like this?
string system = doc.Descendants("dmaddres")
.Single(e => e.Element("chapnum") != null)
.Element("chapnum").Value;
string system = doc.Root.Element("dmaddres").Element("chapnum").Value;
would probably do just as well.

How do I read this xml File?

I have this xml file
<?xml version="1.0" encoding="utf-8" ?>
<parameters>
<parameters
registerLink="linkValue"
TextBox.name="nameValue"
/>
</parameters>
I want to print off "LinkValue" and "nameValue" by code:
Console.WriteLine("registerLink: " + registerLink);
Console.WriteLine("TextBox.name: " + TextBox.name);
Thanks
The easiest API is XLinq (System.Xml.Linq)
var doc = XDocument.Load(fileName);
// This should be parameters/parameter, i follow the question with parameters/parameters
var par = doc.Element("parameters").Element("parameters");
registerLink = par.Attribute("registerLink").Value; // string
Your could use an xml reader like this one
http://msdn.microsoft.com/en-us/library/cc189056%28v=vs.95%29.aspx
Once you have a working sample look here to find out how to open an xml reader from a file stream. File must be located in project directory
http://support.microsoft.com/kb/307548
Once you have that done you can add an open file dialog box to find any file on the computer and even validate the .xml extension and more.
Edit: As you can see in the comments below, Hanks solution is better, faster, and easier. My solution would only be useful if you have huge xml files with tons of data. You may still be interested in the file dialog box as well.

Categories