How to deal with non-fixed xelement? - c#

im using a method to parse a xdocument to an object but i have a situation in this line of code:
var xElementTax = xElementXml.Element(xn + "tax");
var aux = xElementTax.Element(xn + "taxNN").Value;
In the taxNN XName the NN part is a random number, i.e: tax01, tax02, tax03 and goes on. It could be any two digit number.
How can i deal with this situation wheres i dont have a fixed tag? The only fixed part of the tag is the tax word.
Thanks.

Are you looping through all the elements of xElementTax?
If so you can just go with this:
foreach(XElement auxElement in xElementTax.Elements)
{
var aux = auxElement.Value;
// And so on
}
If you want only those which match "taxNN" you can go instead with:
foreach(XElement auxElement in xElementTax.Elements.Where(x => x.Name.ToString().StartsWith(xn + "tax"))
{
var aux = auxElement.Value;
...
}
If there's only going to be one of them you can go with:
XElement auxElement = xElementTax.Elements.Where(
x => x.Name.ToString().StartsWith(xn + "tax").FirstOrDefault();
var aux = auxElement.Value;

Related

Getting list of Variables of map in BPM Metastorm

I'm trying to get list of variables in some map OUTSIDE program automatically. I know I can find them in .process file, with has xml structure.
I also figured out that "x:object" with variable contains "x:Type" ending with "MboField}".
But unfortunately I need to narrow searching criterias more, because I still can't find the main patern to separate variables from other objects.
This is my current code in c#:
var xdoc = XDocument.Load(patches.ProcessFilePatch);
var xmlns = XNamespace.Get("http://schema.metastorm.com/Metastorm.Common.Markup");
IEnumerable<string> values = from x in xdoc.Descendants(xmlns+"Object")
where x.Attribute(xmlns+"Type").Value.ToString().EndsWith("MboField}")
select x.Attribute(xmlns+"Name").Value.ToString();
VariablesInProcessFile = values.ToList();
Any other ways to find Variables among others?
private void getVariablesInProcessFile()
{
var xdoc = XDocument.Load(patches.ProcessFilePatch);
var xmlns = XNamespace.Get("http://schema.metastorm.com/Metastorm.Common.Markup");
var dane = xdoc.Descendants(xmlns + "Object").Where(x => CheckAttributes(x, xmlns)).ToArray();
IEnumerable<string> valuesE = from x in dane.Descendants(xmlns + "Object")
where x.Attribute(xmlns + "Type").Value.ToString().EndsWith("MboField}")
select x.Attribute(xmlns + "Name").Value.ToString();
VariablesInProcessFile = valuesE.ToList();
}
private bool CheckAttributes(XElement x, XNamespace xmlns)
{
var wynik = x.Attribute(xmlns + "Name");
return wynik != null && (wynik.Value == patches.MapName + "Data" || wynik.Value == patches.altMapName + "Data");
}
Where "patches" is my own class containing patch to .process file and possible names of group of Variables, usually related to name of the map.

Parsing XML page to read content

I want to read the url in the XML Page URLString, and I wrote the following code:
XElement xelement = XElement.Load(URLString);
var list = from y in xelement.Descendants(atom + "entry")
select new {
Link = y.Element(atom + "link").Attribute("href").Value
};
The output of list in the debug is 25 url.
I want to get the items into list. How can I loop through the list to get the items inside it using for, while, foreach, etc.?
It's been a while since I've worked with LINQ, but I think you can do this:
XElement xelement = XElement.Load(URLString);
var items = from y in xelement.Descendants(atom + "entry")
select y.Element(atom + "link").Attribute("href").Value;
var list = items.ToList();
At this point, list will be of type List<string> and you can do whatever you want with it.

Parsing an UN XML file in C#

I'm trying to parse an XML file from UN website (http://www.un.org/sc/committees/1267/AQList.xml) using c#.
There is one problem I'm constantly having with this file, and that's the number of child tags varies from one <.INDIVIDUAL.> tag to another. One example is <.FORTH_NAME.> child tag.
I've tried a number of different approaches, but somehow I always seem to be stuck with the same problem, and that's different number of child tags inside <.INDIVIDUAL.> tag.
What I'm trying to achieve is to collect all the tags and their values under one <.INDIVIDUAL.> tag, and then insert only those I want into my database. If a tag is missing, for example <.FOURTH_NAME.>, than I need to insert only first three names into the database, and skip the fourth.
I've tried using Linq to XML, and here are some examples:
XDocument xdoc = XDocument.Load(path);
var tags = (from t in xdoc.Descendants("INDIVIDUALS")
from a in t.Elements("INDIVIDUAL")
select new
{
Tag = a.Name,
val = a.Value
});
foreach (var obj in tags)
{
Console.WriteLine(obj.Tag + " - " + obj.val + "\t");
//insert SQL goes here
}
or:
but this one only collects non empty FOURTH_NAME tags...
var q = (from c in xdoc.Descendants("INDIVIDUAL")
from _1 in c.Elements("FIRST_NAME")
from _2 in c.Elements("SECOND_NAME")
from _3 in c.Elements("THIRD_NAME")
from _4 in c.Elements("FOURTH_NAME")
where _1 != null && _2 != null && _3 != null && _4 != null
select new
{
_1 = c.Element("FIRST_NAME").Value,
_2 = c.Element("SECOND_NAME").Value,
_3 = c.Element("THIRD_NAME").Value,
_4 = c.Element("FOURTH_NAME").Value
});
foreach (var obj in q)
{
Console.WriteLine("Person: " + obj._1 + " - " + obj._2 + " - " + obj._3 + " - " + obj._4);
//insert SQL goes here
}
Any ideas??
Instead of calling Value on the element, consider using a string cast. LINQ to XML safely returns null if the element doesn't exist. Try the following:
var data = XElement.Load(#"http://www.un.org/sc/committees/1267/AQList.xml");
var individuals = data.Descendants("INDIVIDUAL")
.Select(i => new {
First = (string)i.Element("FIRST_NAME"),
Middle = (string)i.Element("SECOND_NAME"),
Last = (string)i.Element("THIRD_NAME")
});
If you want to be more flexible and get all of the name fields, you can do something like the following. (I'll leave the process of grouping individuals as an additional homework assignment ;-)
data.Descendants("INDIVIDUAL").Elements()
.Where (i =>i.Name.LocalName.EndsWith("_NAME" ))
.Select(i => new { FieldName= i.Name.LocalName, Value=i.Value});
Why don't you use XmlSerializer and LINQ instead ?
As explained in this answer, generate your classes by pasting in a new CS file :
menu EDIT > Paste Special > Paste XML As Classes.
Then grab your data as easily as follows :
var serializer = new XmlSerializer(typeof (CONSOLIDATED_LIST));
using (FileStream fileStream = File.OpenRead(#"..\..\aqlist.xml"))
{
var list = serializer.Deserialize(fileStream) as CONSOLIDATED_LIST;
if (list != null)
{
var enumerable = list.INDIVIDUALS.Select(s => new
{
FirstName = s.FIRST_NAME,
SecondName = s.SECOND_NAME,
ThirdName = s.THIRD_NAME,
FourthName = s.FOURTH_NAME
});
}
}
You can then specify any predicate that better suits your needs.
Going this path will be a huge time-saver and less error-prone, no need to use strings to access fields, strong typing etc ...

Check if XML node value already exists in xml file using c#

Please note that I'm new to C# and I learn it right now :) I couldn't find something similar to my problem, so I came here.
I have an application in which I add customers (it's in the final stage). All customers are stored in an XML file. Every single customer gets a new customer number. In my xml file I got an XmlNode called CustNo. Now if the user add a new customer and type in a number which already exist, it should pop up a message box to say that this number already exists. I got this c# code:
XDocument xdoc = XDocument.Load(path + "\\save.xml");
var xmlNodeExist = String.Format("Buchhaltung/Customers/CustNo");
var CustNoExist = xdoc.XPathSelectElement(xmlNodeExist);
if (CustNoExist != null)
{
MessageBox.Show("asdf");
}
And my XML file looks like this:
<Buchhaltung>
<Customers>
<CustNo>12</CustNo>
<Surname>Random</Surname>
<Forename>Name</Forename>
<Addr>Address</Addr>
<Zip>12345</Zip>
<Place>New York</Place>
<Phone>1234567890</Phone>
<Mail>example#test.com</Mail>
</Customers>
<Customers>
<CustNo>13</CustNo>
<Surname>Other</Surname>
<Forename>Forename</Forename>
<Addr>My Address</Addr>
<Zip>67890</Zip>
<Place>Manhattan</Place>
<Phone>0987654321</Phone>
<Mail>test#example.com</Mail>
</Customers>
</Buchhaltung>
But then the message box always pops up. What am I doing wrong?
That's because your XPath return all CustNo elements, no matter of it's content.
Try following:
var myNumber = 12;
var xmlNodeExist = String.Format("Buchhaltung/Customers/CustNo[. = {0}]", myNumber.ToString());
or using First and LINQ to XML:
var myNumber = 12;
var xmlNodeExist = "Buchhaltung/Customers/CustNo";
var CustNoExist = xdoc.XPathSelectElements(xmlNodeExist).FirstOrDefault(x => (int)x == myNumber);
You are currently testing for existance of any 'CustNo' element. See this reference about the XPath syntax.
Your XPath should say something like this:
Buchhaltung//Customers[CustNo='12']
which would say "any customers element containing a 'CustNo' element with value = '12'"
Combining that with your current code:
var custNoGivenByCustomer = "12";
var xmlNodeExistsXpath = String.Format("Buchhaltung//Customers[CustNo='{0}']", custNoGivenByCustomer );
var CustNoExist = xdoc.XPathSelectElement(xmlNodeExistsXpath);
You can use LINQ to XML
var number = textBox1.Text;
var CustNoExist = xdoc.Descendants("CustNo").Any(x => (string)x == number);
if(CustNoExist)
{
MessageBox.Show("asdf");
}
This is because you select the CustNo elements regardless of their value. This will filter it to the desired customer number:
int custNo = 12;
var xmlNodeExist = String.Format("Buchhaltung/Customers[CustNo={0}]", custNo);
It selects the Customers elements instead, but since you're just checking for existence, that's unimportant.
W3Schools has a good tutorial/reference on XPath.

Parse particular text from an XML string

Im writing an app which reads an RSS feed and places items on a map.
I need to read the lat and long numbers only from this string:
http://www.digitalvision.se/feed.aspx?isAlert=true&lat=53.647351&lon=-1.933506
.This is contained in link tags
Im a bit of a programming noob but im writing this in C#/Silverlight using Linq to XML.
Shold this text be extrated when parsing or after parsing and sent to a class to do this?
Many thanks for your assistance.
EDIT. Im going to try and do a regex on this
this is where I need to integrate the regex somewhere in this code. I need to take the lat and long from the Link element and seperate it into two variables I can use (the results are part of a foreach loop that creates a list.)
var events = from ev in document.Descendants("item")
select new
{
Title = (ev.Element("title").Value),
Description = (ev.Element("description").Value),
Link = (ev.Element("link").Value),
};
Question is im not quite sure where to put the regex (once I work out how to use the regex properly! :-) )
try this
var url = "http://www.xxxxxxxxxxxxxx.co.uk/map.aspx?isTrafficAlert=true&lat=53.647351&lon=-1.93350";
var items = url.Split('?')[1]
.Split('&')
.Select(i => i.Split('='))
.ToDictionary(o => o[0], o => o[1]);
var lon = items["lon"];
var lat = items["lat"];
If you only need the Lat and Lon values and the feed is just one big XML string you can do the whole thing with a regular expression.
var rssFeed = #"http://www.xxxxxxxxxxxxxx.co.uk/map.aspx?isTrafficAlert=true&lat=53.647351&lon=-1.933506
http://www.xxxxxxxxxxxxxx.co.uk/map.aspx?isTrafficAlert=true&lat=53.647352&lon=-1.933507
http://www.xxxxxxxxxxxxxx.co.uk/map.aspx?isTrafficAlert=true&lat=53.647353&lon=-1.933508
http://www.xxxxxxxxxxxxxx.co.uk/map.aspx?isTrafficAlert=true&lat=53.647354&lon=-1.933509";
var regex = new Regex(#"lat=(?<Lat>[+-]?\d*\.\d*)&lon=(?<Lon>[+-]?\d*\.\d*)");
var latLongPairs = new List<Tuple<decimal, decimal>>();
foreach (Match match in regex.Matches(rssFeed))
{
var lat = Convert.ToDecimal(match.Groups["Lat"].Value);
var lon = Convert.ToDecimal(match.Groups["Lon"].Value);
latLongPairs.Add(new Tuple<decimal, decimal>(lat, lon));
}

Categories

Resources