I have an XElement that looks like this:
<User ID="11" Name="Juan Diaz" LoginName="DN1\jdiaz" xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/" />
How can I use XML to extract the value of the LoginName attribute? I tried the following, but the q2 "Enumeration yielded no results".
var q2 = from node in el.Descendants("User")
let loginName = node.Attribute(ns + "LoginName")
select new { LoginName = (loginName != null) };
foreach (var node in q2)
{
Console.WriteLine("LoginName={0}", node.LoginName);
}
var xml = #"<User ID=""11""
Name=""Juan Diaz""
LoginName=""DN1\jdiaz""
xmlns=""http://schemas.microsoft.com/sharepoint/soap/directory/"" />";
var user = XElement.Parse(xml);
var login = user.Attribute("LoginName").Value; // "DN1\jdiaz"
XmlDocument doc = new XmlDocument();
doc.Load("myFile.xml"); //load your xml file
XmlNode user = doc.getElementByTagName("User"); //find node by tag name
string login = user.Attributes["LoginName"] != null ? user.Attributes["LoginName"].Value : "unknown login";
The last line of code, where it's setting the string login, the format looks like this...
var variable = condition ? A : B;
It's basically saying that if condition is true, variable equals A, otherwise variable equals B.
from the docs for XAttribute.Value:
If you are getting the value and the attribute might not exist, it is more convenient to use the explicit conversion operators, and assign the attribute to a nullable type such as string or Nullable<T> of Int32. If the attribute does not exist, then the nullable type is set to null.
I ended up using string manipulation to get the value, so I'll post that code, but I would still like to see an XML approach if there is one.
string strEl = el.ToString();
string[] words = strEl.Split(' ');
foreach (string word in words)
{
if (word.StartsWith("LoginName"))
{
strEl = word;
int first = strEl.IndexOf("\"");
int last = strEl.LastIndexOf("\"");
string str2 = strEl.Substring(first + 1, last - first - 1);
//str2 = "dn1\jdiaz"
}
}
Related
I'm developing a web service that will receive a XML string and will compare with the internalName string. I'm using LINQ to parse the XML (and I think I'm doing it correctly) but I'm not sure how to compare the "value" withinternalName, per example.
[WebMethod]
public string WMCompare (string xml, string internalName)
{
XDocument xmlDoc = XDocument.Load(xml);
var result = from ele in xmlDoc.Descendants("property")
select new
{
key = (string)ele.Element("key"),
value = (string)ele.Element("value")
};
foreach (var i in result)
{
}
}
}
Thank you for your attention and I'm sorry about the newbie question. It's my first time working with XML.
Considering that you are comparing string with value:
var newResult = result.Where(r => r.value.Equals(internalName))
Alternatively, you may also compare while parsing your XML:
var result1 = from ele in doc.Descendants("property")
where ele.HasElements && ele.Element("value") != null && ele.Element("value").Equals(internalName)
select new
{
key = (string)ele.Element("key"),
value = (string)ele.Element("value")
};
I'm trying to parse an xml file for the value of an element and then assign that single value to a variable. I understand that I can do this:
XDocument xdoc = XDocument.Load("filename");
string someName;
var name = from n in xdoc.Descendants("name")
select (string)n;
foreach(var n in name )
{
someName = n;
}
My question is how can I do the same thing, but without a foreach loop?
string someName = (string)xdoc.Descendants("name").First();
If you have single name element in your xml file, then either use #abatishchev solution (probably with FirstOrDefault instead of First if element can be missing) or you can use XPath query:
string someName = (string)xdoc.XPathSelectElement("//name");
If you know there is only a single element in name, you can do it like this:
someName = name.Single();
I'm getting a text string from a website and parsing it into an XDocument. I'm looking to feed the value of certain elements into a very simple object (named NWSevent). My problem is that the original string changes and the XML tree varies; sometimes there are numerous events, up to 40, sometimes there is only one, and sometimes there is only one that does not have all the characteristics. If there are no alerts, then the "event" element has a title, but no areaDesc, summary, or severity.
I have two constructors for NWSevent, one takes in a single string, the other takes in four string arguments. I'm having trouble getting around a NullReferenceException. The if statement below can't do it because there is no value to compare. I'd appreciate any help.
public static void ParseWeatherData(String xmlString)
{
String ticker = string.Empty;
XDocument root = XDocument.Parse(xmlString);
XNamespace ns = XNamespace.Get("http://www.w3.org/2005/Atom");
XNamespace nsCap = XNamespace.Get("urn:oasis:names:tc:emergency:cap:1.1");
//get list of entry elements, set conditions for title, areaDesc, etc
var xlist = root.Descendants(ns + "entry").Select(elem => new
{ //use first or default to deal with possiblity of null return
Title = elem.Descendants(ns + "title").FirstOrDefault(),
AreaDesc = elem.Descendants(nsCap + "areaDesc").FirstOrDefault(),
Severity = elem.Descendants(nsCap + "severity").FirstOrDefault(),
Summary = elem.Descendants(ns + "summary").FirstOrDefault()
});
foreach (var el in xlist) //need to address null values when no alerts
{
if (el.AreaDesc.Value != null) //causes yellow null ERROR; no value exists for el.areaDesc.value
{
String titleIn = el.Title.Value;
String areaIn = el.AreaDesc.Value;
String severityIn = el.Severity.Value;
String summaryIn = el.Summary.Value;
new Models.NWSevent(titleIn, areaIn, severityIn, summaryIn);
}
else
{
String titleIn = el.Title.Value;
new Models.NWSevent(titleIn);
}
}
Embarassing! Props to Dweeberly for pointing it out. I just need to change the if statement from
if (el.AreaDesc.Value != null){}
to if (el.AreaDesc != null){}
I'm parsing XML. I normally parse it the way I show in the code below which is straightforward The problem is that I don't own the XML I'm parsing and I can't change it. Sometimes there is no thumbnail element (there are no tags) and I get an Exception.
Is there a way to maintain this simplicity and check if the element exists? Or do I have to get first an XElement list with LINQ, to then check it and fill only the existing object properties?
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
XDocument dataDoc = XDocument.Load(new StringReader(e.Result));
var listitems = from noticia in dataDoc.Descendants("Noticia")
select new News()
{
id = noticia.Element("IdNoticia").Value,
published = noticia.Element("Data").Value,
title = noticia.Element("Titol").Value,
subtitle = noticia.Element("Subtitol").Value,
thumbnail = noticia.Element("Thumbnail").Value
};
itemList.ItemsSource = listitems;
}
[Edit]Jon Skeet's answer should be the accepted answer. It is far more readable and easier to apply.[/edit]
Create an extension method like this :
public static string TryGetElementValue(this XElement parentEl, string elementName, string defaultValue = null)
{
var foundEl = parentEl.Element(elementName);
if (foundEl != null)
{
return foundEl.Value;
}
return defaultValue;
}
then, change your code like this :
select new News()
{
id = noticia.TryGetElementValue("IdNoticia"),
published = noticia.TryGetElementValue("Data"),
title = noticia.TryGetElementValue("Titol"),
subtitle = noticia.TryGetElementValue("Subtitol"),
thumbnail = noticia.TryGetElementValue("Thumbnail", "http://server/images/empty.png")
};
This approach allows you to keep a clean code with isolating the check of element presence. It also allow you to define a default value, which can be helpful
Instead of using the Value property, if you cast to string you'll just get a null reference instead:
void wc_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
XDocument dataDoc = XDocument.Load(new StringReader(e.Result));
var listitems = from noticia in dataDoc.Descendants("Noticia")
select new News()
{
id = (string) noticia.Element("IdNoticia"),
published = (string) noticia.Element("Data"),
title = (string) noticia.Element("Titol"),
subtitle = (string) noticia.Element("Subtitol"),
thumbnail = (string) noticia.Element("Thumbnail")
};
itemList.ItemsSource = listitems;
}
That uses the explicit conversion from XElement to string, which handles a null input by returning a null output. The same is true for all explicit conversions on XAttribute and XElement to nullable types, including nullable value types such as int? - you just need to be careful if you're using nested elements. For example:
string text = (string) foo.Element("outer").Element("inner");
will give a null reference if inner is missing, but will still throw an exception if outer is missing.
If you want a "default" value, you can use the null coalescing operator (??):
string text = (string) foo.Element("Text") ?? "Default value";
You could just use the System.Xml.Serialization.XmlSerializer to deserialize it from xml to an object. Then if the element doesn't exist the property of the object will just get it's default value.
Have a look here: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx
or the new path
https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer
You may use the code below:
string content = item.Element("Content") == null ? "" : item.Element("Content").Value;
How to test whether a node contains particular string or character using C# code.
example:
<abc>
<foo>data testing</foo>
<foo>test data</foo>
<bar>data value</bar>
</abc>
Now I need to test the particular node value has the string "testing" ?
The output would be "foo[1]"
You can also that into an XPath document and then use a query:
var xPathDocument = new XPathDocument("myfile.xml");
var query = XPathExpression.Compile(#"/abc/foo[contains(text(),""testing"")]");
var navigator = xpathDocument.CreateNavigator();
var iterator = navigator.Select(query);
while(iterator.MoveNext())
{
Console.WriteLine(iterator.Current.Name);
Console.WriteLine(iterator.Current.Value);
}
This will determine if any elements (not just foo) contain the desired value and will print the element's name and it's entire value. You didn't specify what the exact result should be, but this should get you started. If loading from a file use XElement.Load(filename).
var xml = XElement.Parse(#"<abc>
<foo>data testing</foo>
<foo>test data</foo>
<bar>data value</bar>
</abc>");
// or to load from a file use this
// var xml = XElement.Load("sample.xml");
var query = xml.Elements().Where(e => e.Value.Contains("testing"));
if (query.Any())
{
foreach (var item in query)
{
Console.WriteLine("{0}: {1}", item.Name, item.Value);
}
}
else
{
Console.WriteLine("Value not found!");
}
You can use Linq to Xml
string someXml = #"<abc>
<foo>data testing</foo>
<foo>test data</foo>
</abc>";
XDocument doc = XDocument.Parse(someXml);
bool containTesting = doc
.Descendants("abc")
.Descendants("foo")
.Where(i => i.Value.Contains("testing"))
.Count() >= 1;