Доброго времени суток!
Столкнулся я с проблемой с которой сталкиваются обычно новички. Вот не сталкивался я за два года с парсингом XML на SF.
Надо запарсить вот это XML: http://api2.aacb.com/get-exchange-rate/?date=20140930
Почитал вот эту статью : https://salesforce-developer.ru/integratsiya-s-force-com-ispolzuem-xml-v-apex-kode-perevod/
Получилось вот так:
[code]
public List<SelectOption> currencies
{
get
{
List<Selectoption> lstcurr = new List<Selectoption>();
List<forxmlparser> lstcls = new List<forxmlparser>();
XmlStreamReader reader = new XmlStreamReader('http://api2.aacb.com/get-exchange-rate/?date=20140930');
forxmlparser cls;
while (reader.hasNext())
{
if (reader.getEventType() == XmlTag.START_ELEMENT)
{
if ('Currency' == reader.getLocalName())
{
cls = new forxmlparser();
}
else if('Name' == reader.getLocalName())
{
cls.strName = getValueFromTag(reader);
}
else if('ExchangeRate' == reader.getLocalName())
{
cls.strCurr = getValueFromTag(reader);
}
}
else if (reader.getEventType() == XmlTag.END_ELEMENT)
{
if ('Currency' == reader.getLocalName())
{
lstcls.add(cls);
}
else if ('CustomExchangeRates' == reader.getLocalName())
{
break;
}
}
}
for(forxmlparser a: lstcls)
{
lstcurr.add(new Selectoption(a.strCurr,a.strName));
}
return lstcurr;
}
set;
}
[/code]
Результат: ошибка Apex CPU time limit exceeded
А где ты переходишь к следующему элементу? Ты работаешь только с первым!
[quote="Виктор Сенько"]Результат: ошибка Apex CPU time limit exceeded [/quote]
А где ты переходишь к следующему элементу?
Ты работаешь только с первым!
[quote="Виктор Сенько"]И что мне надо сделать на данном примере?[/quote]\
Выкинуть этот ужасный способ.Рядом намного приятнее [url=https://salesforce-developer.ru/parsing-xml-i-pravilnoe-sohranenie-dannyih-po-externalid/]ТЫЦ[/url]
Так тоже пробовал
public List<SelectOption> currencies { get { map<String, String> currmap = new map<String, String>(); List<Selectoption> lstcurr = new List<Selectoption>(); DOM.Document doc = new DOM.Document(); doc.load('http://api2.aacb.com/get-exchange-rate/?date=20140930'); DOM.XMLNode root = doc.getRootElement(); if (root.getNodeType() == DOM.XMLNodeType.ELEMENT && root.getName() == 'CustomExchangeRates') { for (Dom.XMLNode child: root.getChildElements()) { if (child.getNodeType() == DOM.XMLNodeType.ELEMENT && child.getName() == 'Currencies') { String nameSt = child.getChildElement('Name', NULL).getText().trim(); String currSt = child.getChildElement('ExchangeRate', NULL).getText().trim(); currmap.put(nameSt,currSt); } } } for(String a: currmap.keyset()) { lstcurr.add(new Selectoption(currmap.get(a),a)); } return lstcurr; } set; }
Ошибка Failed to parse XML due to: only whitespace content allowed before start tag and not h (position: START_DOCUMENT seen h... @1:1) Есть подозрение что я просто не так беру Элеметы по структуре. Но не знаю как по другому.
Так тоже пробовал
[code]
public List<SelectOption> currencies
{
get
{
map<String, String> currmap = new map<String, String>();
List<Selectoption> lstcurr = new List<Selectoption>();
DOM.Document doc = new DOM.Document();
doc.load('http://api2.aacb.com/get-exchange-rate/?date=20140930');
DOM.XMLNode root = doc.getRootElement();
if (root.getNodeType() == DOM.XMLNodeType.ELEMENT && root.getName() == 'CustomExchangeRates')
{
for (Dom.XMLNode child: root.getChildElements())
{
if (child.getNodeType() == DOM.XMLNodeType.ELEMENT && child.getName() == 'Currencies')
{
String nameSt = child.getChildElement('Name', NULL).getText().trim();
String currSt = child.getChildElement('ExchangeRate', NULL).getText().trim();
currmap.put(nameSt,currSt);
}
}
}
for(String a: currmap.keyset())
{
lstcurr.add(new Selectoption(currmap.get(a),a));
}
return lstcurr;
}
set;
}
[/code]
Ошибка Failed to parse XML due to: only whitespace content allowed before start tag and not h (position: START_DOCUMENT seen h... @1:1)
Есть подозрение что я просто не так беру Элеметы по структуре. Но не знаю как по другому.
А не забыл ли ты еще одну ноду <Currency> ? П.С. А дату тянуть тебе не нужно?
[quote="Виктор Сенько"]doc.load('http://api2.aacb.com/get-exchange-rate/?date=20141001');[/quote]
это неправильная конструкция.
[url=https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_xml_dom_document.htm#apex_Dom_Document_load]Document Class (load)[/url]
[quote]
Parse the XML representation of the document specified in the xml argument and load it into a document.
Signature
public Void load([b]String[/b] xml)
Example
Dom.Document doc = new Dom.Document();
doc.load(xml);
[/quote]
xml - это НЕ url, это XML в текстовом виде
public with sharing class MyApexClass { public List<String> currencies { get { List <String> currmap = new List <String>(); List<Selectoption> lstcurr = new List<Selectoption>(); Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('http://api2.aacb.com/get-exchange-rate/?date=20141001'); req.setMethod('GET'); HttpResponse res = h.send(req); Dom.Document doc = res.getBodyDocument(); DOM.XMLNode root = doc.getRootElement(); if (root.getNodeType() == DOM.XMLNodeType.ELEMENT && root.getName() == 'CustomExchangeRates') { for(Dom.XMLNode child: root.getChildElements()) { if (child.getNodeType() == DOM.XMLNodeType.ELEMENT && child.getName() == 'Currencies') { for(Dom.XMLNode child2: child.getChildElements()) { if (child2.getNodeType() == DOM.XMLNodeType.ELEMENT && child2.getName() == 'Currency') { String nameSt = child2.getChildElement('Name', NULL).getText().trim(); String currSt = child2.getChildElement('ExchangeRate', NULL).getText().trim(); currmap.add(nameSt); } } } } } System.debug(currmap); return currmap; } set; } }
А никому не приходило в голову написать сериализацию/десериализацию?
Кст, в новом релизе ее обещают сделать из коробки.
Зачем? Есть же сериализацию/десериализацию в JSON. Отлично работает А для интеграции с API которые кушают XML все равно придется каждый раз подстраиваться.
[quote="Gres"]А никому не приходило в голову написать сериализацию/десериализацию? [/quote]
Зачем? Есть же сериализацию/десериализацию в JSON. Отлично работает :) А для интеграции с API которые кушают XML все равно придется каждый раз подстраиваться.
[quote="Gres"][quote="Dmitry Shnyrev"]А для интеграции с API которые кушают XML все равно придется каждый раз подстраиваться.[/quote]
С чего ты взял?[/quote]
С того что не всегда салесфорс кушает WSDL и генерит правильный прокси класс.
С того что не всегда салесфорс кушает WSDL и генерит правильный прокси класс.
[quote="wilder"]С того что не всегда салесфорс кушает WSDL и генерит правильный прокси класс.[/quote]
Вопрос то был совсем не про wsdl
С того что не всегда салесфорс кушает WSDL и генерит правильный прокси класс.
Вопрос то был совсем не про wsdl
Ок. Объясню развернуто. Предположим нужно общаться с внешним вебсервисом, который отдает тебе XML. Тут есть 2 варианта развития событий : 1. вебсервис имеет WSDL 2. вебсервис не имеет WSDL
В первом случае тоже имеем 2 варианта. 1. Салесфорс создал прокси класс 2. Салесфорс не смог создать прокси класс
Рассмотрим второй случай. Вэтом случае просто придется писать парсер для ответа внешнего сервера. И чем больше методов имеет этот сервис тем больше гемороя отгребаем (если не написать конечно универсальный парсер).
[quote="Gres"][quote="wilder"]С того что не всегда салесфорс кушает WSDL и генерит правильный прокси класс.[/quote]
Вопрос то был совсем не про wsdl[/quote]
Ок. Объясню развернуто. Предположим нужно общаться с внешним вебсервисом, который отдает тебе XML. Тут есть 2 варианта развития событий :
1. вебсервис имеет WSDL
2. вебсервис не имеет WSDL
В первом случае тоже имеем 2 варианта.
1. Салесфорс создал прокси класс
2. Салесфорс не смог создать прокси класс
Рассмотрим второй случай. Вэтом случае просто придется писать парсер для ответа внешнего сервера. И чем больше методов имеет этот сервис тем больше гемороя отгребаем (если не написать конечно универсальный парсер).
Тут человек как раз парсит вручную, а предлагаю написать сериализацию/десериализацию Наверно, это удобнее или ты со мной не согласен?
[quote="Gres"]Тут человек как раз парсит вручную, а предлагаю написать сериализацию/десериализацию
Наверно, это удобнее или ты со мной не согласен?[/quote]
Не согласен, потому как это не универсальный подход.
2. вебсервис не имеет WSDL
я читал, что что JAVA, что .net веб-сервисы могут сами генерить WSDLы описывающие их интерфейс, т.е. сделать WSDL просто. Другое дело что иногда подсовывают устаревшие (необновленные) WSDL...
2. Салесфорс не смог создать прокси класс
в каких случаях Салесфорс не может создать класс-клиент из WSDL? - когда WSDL слишком большой. - слышал на форуме что когда <soap:body use="literal"/> use не литеральный. - когда еще?
другое дело что и сгенеренные класс-клиент нужно допиливать, они даже могут не сохраняться сразу после генерации из-за напрмер повторов в названии полей.
[quote="wilder"]
2. вебсервис не имеет WSDL
[/quote]
я читал, что что JAVA, что .net веб-сервисы могут сами генерить WSDLы описывающие их интерфейс, т.е. сделать WSDL просто. Другое дело что иногда подсовывают устаревшие (необновленные) WSDL...
[quote="wilder"]
2. Салесфорс не смог создать прокси класс
[/quote]
в каких случаях Салесфорс не может создать класс-клиент из WSDL?
- когда WSDL слишком большой.
- слышал на форуме что когда <soap:body use="literal"/> use не литеральный.
- когда еще?
другое дело что и сгенеренные класс-клиент нужно допиливать, они даже могут не сохраняться сразу после генерации из-за напрмер повторов в названии полей.
Тут человек как раз парсит вручную, а предлагаю написать сериализацию/десериализацию Наверно, это удобнее или ты со мной не согласен?
Не согласен, потому как это не универсальный подход.
Именно вот про это я и писал тут. Сам недавно писал ручками парсер xml от hh.ru потому что wsdl не парсился. Не уверен что эта задача подпадает под общие методы и ее можно описать какими-то сериализаторами.
А для интеграции с API которые кушают XML все равно придется каждый раз подстраиваться.
[quote="wilder"][quote="Gres"]Тут человек как раз парсит вручную, а предлагаю написать сериализацию/десериализацию
Наверно, это удобнее или ты со мной не согласен?[/quote]
Не согласен, потому как это не универсальный подход.[/quote]
Именно вот про это я и писал тут. Сам недавно писал ручками парсер xml от hh.ru потому что wsdl не парсился. Не уверен что эта задача подпадает под общие методы и ее можно описать какими-то сериализаторами.
[quote="Gres"][quote="Dmitry Shnyrev"]А для интеграции с API которые кушают XML все равно придется каждый раз подстраиваться.[/quote]
С чего ты взял?[/quote]
Не согласен, потому как это не универсальный подход.
Я не понимаю, почему все время вы ссылаетесь на wsdl.
http://en.wikipedia.org/wiki/Serialization
http://en.wikipedia.org/wiki/Web_Services_Description_Language
2. вебсервис не имеет WSDL
я читал, что что JAVA, что .net веб-сервисы могут сами генерить WSDLы описывающие их интерфейс, т.е. сделать WSDL просто. Другое дело что иногда подсовывают устаревшие (необновленные) WSDL...
2. Салесфорс не смог создать прокси класс
в каких случаях Салесфорс не может создать класс-клиент из WSDL? - когда WSDL слишком большой. - слышал на форуме что когда <soap:body use="literal"/> use не литеральный. - когда еще?
другое дело что и сгенеренные класс-клиент нужно допиливать, они даже могут не сохраняться сразу после генерации из-за напрмер повторов в названии полей.
Попадется WSDL, который имеет кучу инклудов сторонних xsd-схем размазанных по разным нэймспейсам - это точно никак не переварить
[quote="Den Brown"][quote="wilder"]
2. вебсервис не имеет WSDL
[/quote]
я читал, что что JAVA, что .net веб-сервисы могут сами генерить WSDLы описывающие их интерфейс, т.е. сделать WSDL просто. Другое дело что иногда подсовывают устаревшие (необновленные) WSDL...
[quote="wilder"]
2. Салесфорс не смог создать прокси класс
[/quote]
в каких случаях Салесфорс не может создать класс-клиент из WSDL?
- когда WSDL слишком большой.
- слышал на форуме что когда <soap:body use="literal"/> use не литеральный.
- когда еще?
другое дело что и сгенеренные класс-клиент нужно допиливать, они даже могут не сохраняться сразу после генерации из-за напрмер повторов в названии полей.[/quote]
Попадется WSDL, который имеет кучу инклудов сторонних xsd-схем размазанных по разным нэймспейсам - это точно никак не переварить
Потому что, если я правильно понимаю сериализация в XML нужна чтобы из объекта Salesforce получить валидный XML который поймет какой-нибудь сервис (чтобы не составлять этот XML ручками). Собственно для этого и предназначен WSDL, поэтому его тут все и упоминают. А как еще написать сериализатор который удовлетворит потребности всех сервисов которые кушают XML. Как посмотришь у всех абсолютно разные XML на выходе получаются. Или мы про разные вещи говорим?
[quote="Gres"]Я не понимаю, почему все время вы ссылаетесь на wsdl.
http://en.wikipedia.org/wiki/Serialization
http://en.wikipedia.org/wiki/Web_Services_Description_Language[/quote]
Потому что, если я правильно понимаю сериализация в XML нужна чтобы из объекта Salesforce получить валидный XML который поймет какой-нибудь сервис (чтобы не составлять этот XML ручками). Собственно для этого и предназначен WSDL, поэтому его тут все и упоминают. А как еще написать сериализатор который удовлетворит потребности всех сервисов которые кушают XML. Как посмотришь у всех абсолютно разные XML на выходе получаются.
Или мы про разные вещи говорим?
Я говорю про SOAP сервисы, которые умеют работать только с xml, ну и удобно соответственно использовать десериализацию, чтобы рабоатть с объектами. WSDL - язык описания веб сервисов, основанный на хml
Я говорю про SOAP сервисы, которые умеют работать только с xml, ну и удобно соответственно использовать десериализацию, чтобы рабоатть с объектами.
WSDL - язык описания веб сервисов, основанный на хml
Вопрос по парсеру
Вот так вот я достаю элемент:
[code]String nameSt = child2.getChildElement('Name', NULL).getText().trim();[/code]
А как мне достать его атрибут к примеру Price?