I cant seem to get the Linq syntax correct - or I dont know how to reference XML objects.
I have XML like
<?xml version="1.0" encoding="UTF-8"?>
<Targets>
<FileType TargetId="image">
<FileExtension>jpg</FileExtension>
<FileExtension>jpeg</FileExtension>
<FileExtension>tif</FileExtension>
<FileExtension>tiff</FileExtension>
<FileExtension>gif</FileExtension>
<FileExtension>png</FileExtension>
</FileType>
</Targets>
I want to lookup/extract the 'TargetId' where the file extension matches the one I am looking for, say "jpeg"
Firstly, this is the 1st time I am using a structure with a list of the same element names 'FileExtension'. And it never seems to find it.
I am basing this on previous test code where, with XML like...
<body>
<Customers>
<Client TestAttr=""testing-123"">
<Firstname>someguy</Firstname>
<LastName>some other last name again</LastName>
<PhoneNumber>12345634543</PhoneNumber>
<City>some other town</City>
<State>some other state</State>
</Client>
</Customers>
</body>
the code
IEnumerable<XElement> someClients =
from el in doc.Elements("Customers").Elements("Client")
where (string)el.Element("PhoneNumber") == phoneNumberToFind
select el;
does find the one I am looking for. then I can get another element within the same 'Client' with
Console.WriteLine("Found client named '{0}'", (string)el.Element("LastName").Value );
and printing 'el' gives the following - everything is in the one chunk:-
<Client TestAttr="testing-123">
<Firstname>someguy</Firstname>
<LastName>some other last name again</LastName>
<PhoneNumber>12345634543</PhoneNumber>
<City>some other town</City>
<State>some other state</State>
</Client>
Secondly, All my attempts to access the Attribute at the parent level are met with
An unhandled exception of type 'System.NullReferenceException' occurred in ......dll: 'Object reference not set to an instance of an object.'
things tried include
string fTestAttr1= (string)el.Element("Client").Value;
string fTestAttr2= (string)el.Element("Client").Attribute("TestAttr");
string fTestAttr3= (string)el.Element("Client").Attribute("TestAttr").Value;
string fTestAttr4= (string)el.Element("Client").FirstAttribute.Value;
string fTestAttr4= (string)el.Element("Client").FirstAttribute.Value)
So clearly I dont know adress the parent. Not helped by VS Code debug where I cas see 'el' is [XElement] but it does not have any 'Element'
Thanks for any support JC
With the query, it returns IEnumerable
of Client/FileType XElement
. Hence you don't need the extra .Element("Client")
/.Element("FileType")
as it will treat as there is a descendant with Client
/<FileType>
.
Obtain the attribute value: result.Attribute("TargetId").Value
.
string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<Targets>
<FileType TargetId=""image"">
<FileExtension>jpg</FileExtension>
<FileExtension>jpeg</FileExtension>
<FileExtension>tif</FileExtension>
<FileExtension>tiff</FileExtension>
<FileExtension>gif</FileExtension>
<FileExtension>png</FileExtension>
</FileType>
<FileType TargetId=""doc"">
<FileExtension>doc</FileExtension>
</FileType>
</Targets>";
XDocument doc = XDocument.Parse(xml);
XElement root = doc.Root;
XElement result = (from el in doc.Elements("Targets").Elements("FileType")
where el.Elements("FileExtension").Any(x => (string)x == "jpg")
select el).FirstOrDefault();
Console.WriteLine(result.Attribute("TargetId").Value);
Alternatively, working with XPath:
string targetId = root.XPathSelectElement("/Targets/FileType[FileExtension='jpg']").Attribute("TargetId").Value;
The same goes for Client: Obtain the attribute value: result2.Attribute("TestAttr").Value
.
string xml2 = @"<body>
<Customers>
<Client TestAttr=""testing-123"">
<Firstname>someguy</Firstname>
<LastName>some other last name again</LastName>
<PhoneNumber>12345634543</PhoneNumber>
<City>some other town</City>
<State>some other state</State>
</Client>
</Customers>
</body>";
XDocument doc2 = XDocument.Parse(xml2);
XElement root2 = doc2.Root;
XElement result2 = (from el in doc2.Element("body").Elements("Customers").Elements("Client")
where el.Elements("PhoneNumber").Any(x => (string)x == "12345634543")
select el).FirstOrDefault();
Console.WriteLine(result2.Attribute("TestAttr").Value);
Alternatively, working with XPath:
string testAttr = root2.XPathSelectElement("/body/Customers/Client[PhoneNumber=12345634543]").Attribute("TestAttr").Value;