Почему не работает цикл (не обходится второй узел)?
Подскажите пожалуйста где ошибка! Вот фрагмент XML:
<MessageInfo MessageType="StartOfExtrajudicialBankruptcy">
<StartOfExtrajudicialBankruptcy>
<CreditorsNonFromEntrepreneurship>
<MonetaryObligations>
<MonetaryObligation>
<CreditorName>ао тинькофф банк</CreditorName>
<CreditorRegion>г. Москва</CreditorRegion>
<CreditorLocation>123060 г. москва 1-й волоколамский проезд 10</CreditorLocation>
<Content>кредитный договор</Content>
<Basis>кредитный договор №0219164910 от 08.09.2016</Basis>
<TotalSum>220449.4</TotalSum>
<DebtSum>220449.4</DebtSum>
<PenaltySum xsi:nil="true" />
</MonetaryObligation>
<MonetaryObligation>
<CreditorName>поа сбербанк</CreditorName>
<CreditorRegion>Рязанская область</CreditorRegion>
<CreditorLocation>рязань ул. пожалостина, 19</CreditorLocation>
<Content>кредитный договор</Content>
<Basis>кредитный договор</Basis>
<TotalSum>46590.94</TotalSum>
<DebtSum>46590.94</DebtSum>
<PenaltySum xsi:nil="true" />
</MonetaryObligation>
</MonetaryObligations>
<ObligatoryPayments />
</CreditorsNonFromEntrepreneurship>
<IsIndividualEntrepreneur>false</IsIndividualEntrepreneur>
<CreditorsFromEntrepreneurship>
<MonetaryObligations />
<ObligatoryPayments />
</CreditorsFromEntrepreneurship>
<Banks />
<TaxOffices />
</StartOfExtrajudicialBankruptcy>
Вот код:
XmlNode MonetaryObligation = messageRoot.SelectSingleNode("//MessageInfo/StartOfExtrajudicialBankruptcy/CreditorsNonFromEntrepreneurship/MonetaryObligations/MonetaryObligation");
foreach (XmlNode childnode in MonetaryObligation.ChildNodes) {
if (childnode.Name == "CreditorName") Console.WriteLine($"Банк: {childnode.InnerText}");
if (childnode.Name == "TotalSum") Console.WriteLine($"Сумма: {childnode.InnerText}");
}
Console.WriteLine(" ------end-----");
Вывод:
Банк: ао тинькофф банк
Сумма: 220449.4
------end-----
Почему выводится информация только по первому банку?
Ответы (2 шт):
Сделайте так
XmlNode MonetaryObligations = messageRoot.SelectSingleNode("//MessageInfo/StartOfExtrajudicialBankruptcy/CreditorsNonFromEntrepreneurship/MonetaryObligations");
foreach (XmlNode MonetaryObligation in MonetaryObligations.ChildNodes) {
foreach (XmlNode childnode in MonetaryObligation.ChildNodes) {
if (childnode.Name == "CreditorName") Console.WriteLine($"Банк: {childnode.InnerText}");
if (childnode.Name == "TotalSum") Console.WriteLine($"Сумма: {childnode.InnerText}");
}
}
Console.WriteLine(" ------end-----");
Во избежание второго цикла попробуйте его переписать так
Console.WriteLine($"Банк: {MonetaryObligation["CreditorName"].InnerText}");
Console.WriteLine($"Сумма: {MonetaryObligation["TotalSum"].InnerText}");
У вас изначально неверная логика работы, ибо вы ищете первый попавшийся MonetaryObligation, а потом "пляшете" от него, взят все дочерние элементы, зачем эти лишние действия, если можно сразу взять то, что вы хотите. Давайте так и поступим:
Меняем
.SelectSingleNode()на.SelectNodes(), ибо он берет все найденные элементы, соответствующие данномуXPath. Получаем такое:var MonetaryObligation = messageRoot.SelectNodes("//MessageInfo/StartOfExtrajudicialBankruptcy/CreditorsNonFromEntrepreneurship/MonetaryObligations/MonetaryObligation");Далее убираем
.ChildNodesуforeach, ибо предыдущий шаг нам уже выдал коллекцию нужных нам объектов.foreach (XmlNode childnode in MonetaryObligation)Теперь вывод, меняем его на примерно такой вид:
Console.WriteLine($"Банк: {childnode["CreditorName"]?.InnerText}"); Console.WriteLine($"Сумма: {childnode["TotalSum"]?.InnerText}");Думаю, вы уже поняли, что у нас на руках сейчас нода
<MonetaryObligation>, из нее то мы и получаем необходимые значения, просто, по ключу, а знак?(вопроса) не даст выполниться правой части кода, если такого значения нету и выведет просто пустоту.
Собственно весь код будет таким:
var MonetaryObligation = messageRoot.SelectNodes("//MessageInfo/StartOfExtrajudicialBankruptcy/CreditorsNonFromEntrepreneurship/MonetaryObligations/MonetaryObligation");
foreach (XmlNode childnode in MonetaryObligation)
{
Console.WriteLine($"Банк: {childnode["CreditorName"]?.InnerText}");
Console.WriteLine($"Сумма: {childnode["TotalSum"]?.InnerText}");
}
Console.WriteLine(" ------end-----");
Немного полезного.
Если вы в
XPathпишете//, то это означает "искать по всему документу и всем нодам", да, думаю вы уже догадались, что не обязательно писать весь путь и весьXPathсводится к простому"//MonetaryObligation".В C# есть как по мне, более продвинутая и удобная версия парсера XML, зовется
XDocument(изSystem.Xml.Linq) и там вам вообщеXPathне понадобиться, ибо если переписать код выше на него, то выйдет нечто такое:foreach (var obligation in xDoc.Descendants("MonetaryObligation")) { Console.WriteLine($"Банк: {obligation.Element("CreditorName")?.Value}"); Console.WriteLine($"Сумма: {obligation.Element("TotalSum")?.Value}"); }Как видите, ни единой строчки
XPath, а лишь простые методы.Element(),.Elements(),.Descendants(), да и значение сразу.Value. Это конечно дело вкусов и на этом примере особо не показать что с ним можно, но как вариант, знайте.Ну а вообще, я вам настоятельно рекомендую при работе с подобными объектами, в первую очередь, искать способы их десериализации/сериализации, ибо когда у вас данные храниться в классе, это не только удобно, но и сберегает кучу нерв и сил в дальнейшем, ибо если вдруг в вашем XML измениться хоть одно название, то вы будете искать во всем проекте где вы его используете в виде простой строки, а имея класс, вам надо лишь поменять название нужного свойство и во всех других местах вы сразу получите ошибку о несущесвующем имени.