Проблемы с получением данных из XML -файла
-
29-09-2019 - |
Вопрос
Я пытаюсь проанализировать некоторую информацию из Google Geoocoding API, но у меня есть небольшие проблемы с эффективным выводом данных из XML. См. Например, ссылка
Все, что меня действительно волнует, это получение short_name
от address_component
где тип administrative_area_level_1
и long_name
от administrative_area_level_2
Однако с моей тестовой программой мой запрос XPath не возвращает результатов для обоих запросов.
public static void Main(string[] args)
{
using(WebClient webclient = new WebClient())
{
webclient.Proxy = null;
string locationXml = webclient.DownloadString("http://maps.google.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false");
using(var reader = new StringReader(locationXml))
{
var doc = new XPathDocument(reader);
var nav = doc.CreateNavigator();
Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/address_component[type=administrative_area_level_1]/short_name").InnerXml);
Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/address_component[type=administrative_area_level_2]/long_name").InnerXml);
}
}
}
Может ли кто -нибудь помочь мне найти то, что я делаю не так, или рекомендую лучше?
Решение
Вам нужно поместить значение узела, который вы ищете в кавычках:
".../address_component[type='administrative_area_level_1']/short_name"
↑ ↑
Другие советы
Я определенно рекомендую использовать LINQ для XML вместо Xpathnavigator. По моему опыту, это заставляет XML -запрос на ветерок. В этом случае я не уверен, что именно не так ... но вместо этого я приду к фрагменту LINQ в XML.
using System;
using System.Linq;
using System.Net;
using System.Xml.Linq;
class Test
{
public static void Main(string[] args)
{
using(WebClient webclient = new WebClient())
{
webclient.Proxy = null;
string locationXml = webclient.DownloadString
("http://maps.google.com/maps/api/geocode/xml?address=1600"
+ "+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false");
XElement root = XElement.Parse(locationXml);
XElement result = root.Element("result");
Console.WriteLine(result.Elements("address_component")
.Where(x => (string) x.Element("type") ==
"administrative_area_level_1")
.Select(x => x.Element("short_name").Value)
.First());
Console.WriteLine(result.Elements("address_component")
.Where(x => (string) x.Element("type") ==
"administrative_area_level_2")
.Select(x => x.Element("long_name").Value)
.First());
}
}
}
Сейчас является больше кода1... но лично мне легче получить правильно, чем XPath, потому что компилятор помогает мне больше.
РЕДАКТИРОВАТЬ: Я чувствую, что стоит узнать немного больше о том, почему я в целом Предпочитайте такой код, как это, используя XPath, хотя он явно дольше.
Когда вы используете XPath в программе C#, у вас есть два разных языка, но только один находится в контроле (C#). XPath переживается в сферу строк: Visual Studio не дает выражению XPath какую -либо специальную обработку; это не так понимать что это должно быть выражением XPath, так что это не может вам помочь. Дело не в том, что Visual Studio не знает о XPath; Как указывает Dimitre, он вполне способен обнаружить ошибки, если вы редактируете файл XSLT, просто не файл C#.
Это тот случай, когда у вас есть один язык, встроенный в другой, и инструмент не знает об этом. Общие примеры:
- SQL
- Обычные выражения
- HTML
- Xpath
Когда код представлен как данные на другом языке, вторичный язык теряет много своих преимуществ инструмента.
Пока ты могу Контекст переключатель повсюду, вытягивая XPath (или SQL, или регулярные выражения и т. Д.) В свой собственный инструмент (возможно, в рамках той же фактической программы, но в отдельном файле или окне) я считаю, что это делает более труднее для чтения код в долгосрочной перспективе. Если код был написан только когда -либо и никогда не читал потом, это может быть хорошо - но вы делать Нужно иметь возможность читать код впоследствии, и я лично верю, что читаемость страдает, когда это происходит.
Версия LINQ -XML выше используется только строки для чистых данных - имена элементов и т. Д. - и использует код (методы вызовы) для представления таких действий, как «Найдите элементы с данным именем» или «применить этот фильтр». Это более идиоматический код C#, по моему мнению.
Очевидно, что другие не разделяют эту точку зрения, но я подумал, что стоит расширить, чтобы показать, откуда я.
Обратите внимание, что это не сложно и быстро правило Конечно ... в некоторых случаях XPATH, регулярные выражения и т. Д. - лучшее решение. В этом случае я бы предпочел LINQ XML, вот и все.
1 Конечно я мог сохранили каждый Console.WriteLine
Позвоните в одну строку, но я не люблю публиковать код с горизонтальными полосами свитки. Обратите внимание, что написание правильной версии xPath с тем же углублением, что и вышеупомянутое, и избегать прокрутки все еще довольно неприятно:
Console.WriteLine(nav.SelectSingleNode("/GeocodeResponse/result/" +
"address_component[type='administrative_area_level_1']" +
"/short_name").InnerXml);
В целом, длинные линии работают намного лучше в Visual Studio, чем на переполнении стека ...
Я бы порекомендовал просто ввести выражение XPath как часть файла XSLT в Visual Studio. Отказ Вы получите сообщения об ошибках «при печати» - это отличный редактор XML/XSLT/XPath.
Например, я печатаю:
<xsl:apply-templates select="@* | node() x"/>
и немедленно попасть в окно списка ошибок следующей ошибкой:
Error 9 Expected end of the expression, found 'x'. @* | node() -->x<--
XSLTFile1.xslt 9 14 Miscellaneous Files
Только когда выражение xPath не выражает никаких ошибок (я также могу проверить, что оно выбирает также намеченные узлы), я бы вложил это выражение в свой код C#.
Это гарантирует, что у меня не будет XPath - Syntax и Semantic - ошибки, когда я запускаю программу C#.
Ответ DTB является точным. Я хотел добавить, что вы можете использовать инструменты тестирования XPath, такие как ссылка ниже, чтобы помочь найти правильный XPath:
string url = @"http://maps.google.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=false";
string value = "administrative_area_level_1";
using(WebClient client = new WebClient())
{
string wcResult = client.DownloadString(url);
XDocument xDoc = XDocument.Parse(wcResult);
var result = xDoc.Descendants("address_component")
.Where(p=>p.Descendants("type")
.Any(q=>q.Value.Contains(value))
);
}
Результатом является перечисление «ADDRED_CONONTEN» S, у которого есть хотя бы один узел типа «типа», который содержит значение, которое вы ищете. Результатом приведенного выше запроса является Xelement, который содержит следующие данные.
<address_component>
<long_name>California</long_name>
<short_name>CA</short_name>
<type>administrative_area_level_1</type>
<type>political</type>
</address_component>
Я бы действительно рекомендовал потратить немного времени на изучение LINQ в целом, потому что он очень полезен для манипулирования и запроса объектов в памяти, запроса баз данных и, как правило, проще, чем использование XPath при работе с XML. Мой любимый сайт для ссылки http://www.hookedonlinq.com/