Кажется, я не могу правильно понять синтаксис Linq - или я не знаю, как ссылаться на объекты XML.
У меня есть 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>
</Targets>
Я хочу найти/извлечь «TargetId», где расширение файла соответствует тому, которое я ищу, например «jpeg».
Во-первых, я впервые использую структуру со списком одинаковых имен элементов FileExtension. И, кажется, никогда не находит его.
Я основываю это на предыдущем тестовом коде, где с помощью XML типа...
<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>
код
IEnumerable<XElement> someClients =
from el in doc.Elements("Customers").Elements("Client")
where (string)el.Element("PhoneNumber") == phoneNumberToFind
select el;
находит того, кого ищу. тогда я могу получить другой элемент в том же «Клиенте» с помощью
Console.WriteLine("Found client named '{0}'", (string)el.Element("LastName").Value );
и печать «el» дает следующее - все находится в одном куске: -
<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>
Во-вторых, все мои попытки получить доступ к атрибуту на родительском уровне встречают
An unhandled exception of type 'System.NullReferenceException' occurred in ......dll: 'Object reference not set to an instance of an object.'
пробовали включать в себя
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)
Так что я явно не знаю адреса родителя. Не помогает отладка VS Code, где я вижу, что «el» - это [XElement], но у него нет никакого «Element».
Спасибо за любую поддержку Джей Си
По запросу он возвращает IEnumerable
Client/FileType XElement
. Следовательно, вам не нужен дополнительный .Element("Client")
/.Element("FileType")
, поскольку он будет обрабатываться так, как есть потомок с Client
/<FileType>
.
Получите значение атрибута: 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);
Альтернативно работа с XPath:
string targetId = root.XPathSelectElement("/Targets/FileType[FileExtension='jpg']").Attribute("TargetId").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);
Альтернативно работа с XPath:
string testAttr = root2.XPathSelectElement("/body/Customers/Client[PhoneNumber=12345634543]").Attribute("TestAttr").Value;
Юг - спасибо тебе за это. Получение атрибута сработало. Кажется, моя ошибка заключалась в включении слишком большого количества в этом случае '.Element("Client")'. Однако для "найти" - со списком "FileExtension" это работает только для первого в списке, т.е. сверху, это будет найдите «jpg» или «doc», но не «tiff». Может ли это быть как-то связано с FirstOrDefault? Это фундаментальное различие между моей попыткой (которая вернула сет) и вашей, нацеленной на один результат – что, очевидно, будет лучше, если я смогу понять это лучше. еще раз спасибо
Привет, потому что Element
получит первый элемент. Если вы хотите найти какой-либо элемент, вам следует работать с Elements()
и Any()
. Пожалуйста, проверьте мой последний ответ. Спасибо.
Ён, еще раз спасибо. Ваши предложения работают (конечно), но я думаю, что решения XPath, которые вы предлагаете, гораздо легче понять новичку, такому как я.
Все, что вам нужно сделать, это изменить «select el», который возвращает весь элемент в одном фрагменте, на следующее: select new { firstname = (string)el.Element("Firstname"), Lastname = (string)el.Element( "Фамилия")}; При использовании Linq Value выдаст ошибку, если у вас есть ноль. Использование приведения, как я, позволит избежать нулевой ошибки.