вторник, 29 декабря 2009 г.

Преобразуем XML в JSON с помощью XStream


Иногда возникает задача преобразовать существующий XML-документ в эквивалентное ему JSON-представление. Например, такая задача может возникнуть, если вы разрабатываете AJAX-интерфейс к существующей системе, которая генерирует XML. Дело в том, что из JavaScript гораздо проще оперировать объектами, представленными в формате JSON, нежели XML, просто потому что первый формат - нативный.

Так вот, быстро преобразовать XML в JSON можно с помощью замечательной библиотеки XStream, подробное введение в которую опубликовано в статье xstream - сериализуем Java-класс в XML. В состав данной библиотеки входит драйвер JettisonMappedXmlDriver, отвечающий за быстрое преобразование XML -> JSON. Порядок преобразования следующий:


1. Создаем объект класса, реализующего интерфейс HierarchicalStreamReader, способный читать XML. Самой быстрой реализацией является класс XppReader.

2. Создаем объект класса JettisonMappedXmlDriver, кстати, данный класс реализует интерфейс HierarchicalStreamWriter.

3. С помощью метода HierarchicalStreamCopier#copy копируем данные из reader во writer.

Java-кодом этот несложный алгоритм записывается так:

import java.io.StringReader;

import java.io.StringWriter;



import com.thoughtworks.xstream.io.HierarchicalStreamReader;

import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

import com.thoughtworks.xstream.io.copy.HierarchicalStreamCopier;

import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;

import com.thoughtworks.xstream.io.xml.XppReader;





public class Test

{



    public static void main(String[] args)

    {

        String xml = "<user>" +

                        "<name>Pavel</name>" +

                        "<sername>Samolisov</sername>" +

                        "<age>23</age>" +

                        "<rating>89.93</rating>" +

                     "</user>";



        StringWriter buffer = new StringWriter();



        HierarchicalStreamReader reader = new XppReader(new StringReader(xml));

        HierarchicalStreamWriter writer = new JettisonMappedXmlDriver().createWriter(buffer);



        HierarchicalStreamCopier copier = new HierarchicalStreamCopier();

        copier.copy(reader, writer);



        System.out.println(buffer);

    }

}

 


Для запуска примера потребуются следующие библиотеки, входящие в дистрибутив XStream:
jettison
stax-api
xpp3_min
xstream

В результате будет сгенерирована следующая строка в формате JSON:

{"user":{"name":"Pavel","sername":"Samolisov","age":"23","rating":"89.93"}}


Желающие могут померить производительность данной схемы, думаю она будет достаточной для большинства бизнес-приложений.

Понравилось сообщение - подпишитесь на блог или читайте меня в twitter

11 комментариев:

Кай комментирует...

Ключевым недостатком XStream для меня стало то, что он не может создавать JSON код вида [var:result, var2:result], а только вида {root:[var:result, var2:result]}, были и другие заморочки с преобразованием типов, которые я решать уже не стал.

Поэтому я воспользовался библиотечкой Jackson (http://jackson.codehaus.org/), которая прекрасно "искаропки" интегрируется со spring-mvc и проблем с которой пока ещё не было.

Pavel Samolisov комментирует...

Хм, спасибо за наводку, посмотрю Jackson.

Анонимный комментирует...

Мне и то и другое показалось неудобным.
Допустим, у меня есть ряд бизнес объектов. В разных view мне их надо отобразить по разному и в разных комбинациях. Описанные преобразования накладывают ограничения на мои объекты. Приходиться делать специальные объекты обертки и копировать нужные свойства в нужном порядке. Ситуация ухудшается при использовании нескольких разных javascript компонентов.
Самым простым и легко расширяемый способом преобразования показался jsp. Понятно, что в случае изменений бизнес объекта, придется попотеть, но к счастью это случается не часто.

Анонимный комментирует...

Попробуем так, спасибо!

Аленьков Виктор комментирует...

Кай, неправда ваша! если немного погуглить (что я и сделал, когда столкнулся с такой же "проблемой"), то получаем вот такой код при объявлении:

XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
public HierarchicalStreamWriter createWriter(Writer writer) {
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});

Константин комментирует...

Скажите, а не проще ли использовать XSLT для преобразования XML в JSON?

Виктор Аленьков комментирует...

Константин, покажите универсальный пример, подходящий под XML любой структуры - может быть и правда проще будет.

Константин комментирует...

Сомневаюсь, что существует такой "универсальный пример, подходящий под XML любой структуры", Виктор. Но мне кажется, что в большинстве случаев требуется нечто большее, чем прямое преобразование данных из одного формата в другой (XML <-> JSON, например). В моей практике я постоянно сталкиваюсь с тем, что получаемые данные надо ещё как-то модифицировать перед представлением (например, gjkexbnm новые значения на основе имеющихся, создать из плоского списка дерево и т. п.). Вот я и спрашиваю, что в данном случае будет эффективнее: XSLT-преобразование или использование XStream?

Pavel Samolisov комментирует...

ИМХО здесь надо тестировать причем в каждом конкретном случае результаты могут быть разные. Опять же, что значит "Эффективнее"

Константин комментирует...

Эффективнее, в моём понимании, значит быстрее и с наименьшим расходованием ресурсов.

Виктор Аленьков комментирует...

Стоп, народ.

Если мы говорим про сериализацию, то при чем тут "надо ещё модифицировать перед представлением".
А если мы говорим о преобразовании данных, то тут уже выбирать под задачу надо - где-то XSLT сподручнее будет, а где-то и XStream. ни то ни другое не есть панацея от всех "бед"

Отправить комментарий

Любой Ваш комментарий важен для меня, однако, помните, что действует предмодерация. Давайте уважать друг друга!