Логин:   Пароль:






Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100
Rambler's Top100

Мобильная Java: СтатьиОбработка XML в J2ME-приложениях

Обработка XML в J2ME-приложениях

Все больше и больше корпоративных Java-проектов используют XML в качестве стандартного средства для хранения данных для того, чтобы сделать их транспортабельными и доступными другим приложениям и сервисам. Однако из-за высоких требований XML-парсеров к вычислительной мощности, J2ME-приложения в большинстве своем не могли воспользоваться XML для хранения каких-либо данных. Однако сейчас можно найти XML-парсеры, которые не требуют много места и не сильно прихотливы к количеству системных ресурсов. Таким образом, MIDP-программисты уже сегодня могут пользоваться XML в своих приложениях для мобильных устройств. В этой статье мы рассмотрим пример одного такого приложения.

Совместное использование технологий Java и XML представляет очень мощную и эффективную комбинацию переносимого кода и переносимых данных. Но каким образом этот синтез можно заставить работать на платформе Java 2, Micro Edition (J2ME)? В этой статье мы рассмотрим пример одного из урезанных XML-парсеров, который был сжат до таких размеров, что его стало возможным использовать в J2ME-приложениях на платформах с ограниченными системными ресурсами. Для написания нашего приложения для MIDP-платформы, которое будет разбирать XML-документы, мы будем использовать пакет kXML. Но для начала сделаем обзор XML-парсеров и определим, почему они так долго шли к тому, чтобы перейти на платформу J2ME.

Обзор XML-парсеров

Модель обработки XML описывает шаги-операции, которые должно выполнить приложение для обработки полной XML; приложения, которые реализуют такую модель, принято называть XML-парсерами. Вы можете достаточно просто интегрировать любой XML-парсер в любые Java-приложения с помощью Java API for XML Processing (JAXP). JAXP позволяет приложениям разбирать и преобразовывать XML-документы с помощью API, который не зависит от определенной реализации XML-процессора. Благодаря plug-in-подобному механизму, разработчики могут менять реализацию XML-процессора (XML-парсер) на другую без необходимости изменять код самого приложения.

Процесс разбора XML проходит в три фазы:
1. Обработка входного XML-файла. На этой стадии приложение разбирает исходный документ и осуществляет проверку на соответствие его всем стандартам (спецификации), распознает и ищет нужную информацию по его местоположению или имени тегов в исходном документе; извлекает эту информацию, как только она была обнаружена и, опциально, отображает эту информацию в бизнес-объекты.
2. Отработка описанной бизнес-логики. Это стадия, на которой выполняется фактическая обработка получаемой информации. Результатом работы на этой стадии может явиться генерация выходной информации.
3. Обработка выходного представления XML-файла. На этой стадии приложение конструирует модель документа, которая будет представлена с помощью DOM-дерева (Document Object Model). После чего, для получения выходного формата применяются таблицы стилей XSLT или же просто DOM-объект сериализуется напрямую в XML.

SAX (Simple API for XML) и DOM - это наиболее общие модели обработки XML. Если вы используете парсер на основе SAX для обработки XML-документа, вам будет необходимо определить методы для обработки событий, выбрасываемых парсером в случае, когда он обнаружит очередной опознавательный знак языка разметки. Поскольку SAX-парсер генерирует кратковременный поток событий, процесс обработки входного XML-файла (первая фаза разбора XML, упомянутая выше) будет выполнена в одном цикле: каждое возникшее событие немедленно обрабатывается и нужная информация также извлекается автоматически.

В случае, когда вы используете парсеры на основе модели DOM, вам необходимо будет написать код, который бы проходил по структуре данных типа "дерево" и мог выбирать оттуда нужную информацию. Это дерево будет автоматически создано парсером при разборе XML-документа из исходного файла. При использовании этой модели, для выполнения первой фазы разбора XML необходимо выполнить уже не один цикл операций, а два. Во-первых, DOM-парсер создает древовидную структуру, которая обычно называется DOM-деревом и моделирует исходный XML-документ. А во-вторых, приложение должно обойти это DOM-дерево, чтобы найти в нем нужную информацию и извлечь ее из него для дальнейшей обработки. Последний цикл, если необходимо, может проходить сколь угодно большое количество раз подряд, пока DOM-дерево все еще существует в памяти компьютера.

Парсеры, работающие по какой-нибудь из двух рассмотренных выше моделей, требуют достаточно большого объема оперативной памяти и вычислительной мощности, которые не могут предоставить нам многие J2ME-устройства. Для того чтобы обойти эти ограничения были придуманы парсеры третьего типа. Такие парсеры читают документ небольшими кусками. Приложение с помощью парсера проходит по документу, постепенно запрашивая очередную его часть. Самым ярким представителем парсеров третьего типа можно назвать kXML. Именно с его помощью мы и будем писать J2ME-приложение, работающее с XML-данными, в этой статье.

Обработка XML в среде MIDP

Вы можете использовать XML-парсеры в ваших J2ME-приложениях для того, чтобы иметь возможность взаимодействовать с уже существующими XML-сервисами. Например, вы можете получать список новостей на определенную тему, который можно просматривать в удобном вам виде на вашем телефоне с сайта-поставщика новостей на какую-то тему. Обычно информация о новостях на таких сайтах, а именно заголовки новостей и описания к ним, хранятся в формате XML.

Поскольку, как уже говорилось ранее, обычные XML-парсеры слишком громоздки, чтобы J2ME-устройства могли удовлетворить их потребности в оперативной памяти, для работы в MIDP-среде нужны небольшие парсеры, способные работать даже на столь ограниченных системными ресурсами устройствах. Помимо этого эти парсеры должны быть максимально портабельными, чтобы без лишних усилий их можно было портировать на MIDP.

Существует два наиболее популярных XML-парсера, которые обычно используются для работы на устройствах с ограниченными системными ресурсами. Это kXML и NanoXML. kXML был написан специально для использования на J2ME-платформе (CLDC и MIDP). Что же касается NanoXML, то его версия 1.6.8 для MIDP уже имеет поддержку разбора XML по модели DOM (за более подробной информацией по NanoXML и kXML обращайтесь к ссылкам, приведенным в конце этой статьи).

Проблемы производительности

Существует ряд проблем производительности приложений, которые вы должны иметь в виду при разборе XML в своих MIDP-приложениях:

-Увеличенный размер. Использование XML-парсеров зачастую приводит к значительному увеличению кода приложения. Это особенно болезненно в случае с MIDP-устройствами. Однако существует несколько приемов, применив которые, вы, возможно, сможете избежать излишнего расширения кода вашего приложения. Во-первых, вы должны удалить файлы ресурсов, которые вы используете. Помимо этого, крайне желательно воспользоваться обфускаторами (obfuscators), которые удалят за вас неиспользуемые классы, методы и различные переменные из JAD-файла.
- Разбор крупных строк. XML-парсеры используют нагруженные строки для выполнения своей работы. Таким образом, они сильно перегружают MIDP-приложения, оставляя для его работы слишком мало оперативной памяти. XML-документы для разбора в J2ME-приложениях должны состоять только из небольших строк и содержать как можно больше именно полезной (необходимой) информации.
- Медлительные отклики. Как только MIDP-приложение приступит к разбору относительно больших объемов XML-данных, то время на их обработку очевидно возрастет. Поэтому XML-файлы, которые будут разбираться, должны быть небольшими и обработка этих файлов должна происходить в отдельном вычислительном потоке от основного приложения.

В приложении, которое мы будем писать в этой статье, мы естественно будем придерживаться некоторых этих рекомендаций.

Разбор XML в J2ME-приложении

В этой части статьи, приступим к разработке J2ME-приложения, ParseXML, которое будет разбирать XML-документы в формате стандарта RSS (Rich Site Summary) и отображать информацию, закодированную в этих документах на экране телефона. RSS - это сравнительно простой XML-формат, который определяет стандарт определения заголовков и описаний новостей, которые размещаются на новостном или обычном сайтах. Ниже приведен пример RSS-документа:

<?xml version="1.0"?>
<!DOCTYPE rss PUBLIC
"-//Netscape Communications//DTD RSS 0.91//EN"
"http://my.netscape.com/publish/formats/rss-0.91.dtd"
>
<rss version="0.91">
<channel>
<title>Meerkat: An Open Wire Service</title>
<link>http://meerkat.oreillynet.com</link>
<description>
Meerkat is a Web-based syndicated content reader based on RSS ("Rich Site Summary").
RSS is a fantastic, simple-yet-powerful syndication system rapidly gaining momentum.
</description>
</channel>
</rss>

Во время выполнения ParseXML выводит на экран телефона заголовок и описание к нему, которые он берет из приведенного выше RSS-файла. Все вопросы организации пользовательского интерфейса (UI) берет на себя пакет javax.microedition.lcdui.

В этом приложении используется XML-парсер kXML версии 1.2. Для того чтобы сделать классы kXML доступными приложению, необходимо скачать файл kxml.zip. Он содержит все пакеты этого парсера. Этот файл можно найти на официальном сайте проекта kXML (смотрите раздел "Ресурсы" в конце статьи). После этого необходимо скопировать содержимое архива в нужную папку разрабатываемой вами системы. Если вы используете инструментарий J2ME от Sun (смотри раздел "Ресурсы"), то скопировать содержимое архива следует в TOOLKIT_HOME\apps\ParseXML\lib.

В начале своей работы J2ME-приложение выводит текстовое поле, кнопку, при нажатии на которую посылается запрос на вывод разобранных данных XML, и кнопку выхода Exit. При нажатии на кнопку "Display XML" вызывается метод viewXML(). В этом методе, приложение создает экземпляр класса XMLParser, который и будет служить обработчиком XML-документа. При нахождении очередной записи, парсер будет искать содержимое этого элемента: title и description, чтобы найти текст, который нужно вывести на дисплей телефона. Этот процесс протекает рекурсивно. Пользователь может прервать его в любой момент, нажав кнопку Exit.

RSS-данные будут доступны ParseXML в форме объекта класса String. Поскольку XML-парсер работает только с потоком байт, то объект класса String конвертируется в массив байтов. Этот массив используется для создания объекта класса ByteArrayInputStream. В свою очередь, ByteArrayInputStream используется для создания экземпляра класса InputStreamReader, который создает экземпляр класса ParseXML. Это процесс проиллюстрирован в листинге, приведенном ниже:

byte[] xmlByteArray = xmlStr.getBytes();
ByteArrayInputStream xmlStream = new
ByteArrayInputStream( xmlByteArray );
InputStreamReader xmlReader = new
InputStreamReader( xmlStream );
XmlParser parser = new XmlParser( xmlReader );

Для того чтобы получить данные с новостного или любого другого сайта, приложение должно открыть URL-соединение и прочитать RSS-данные из полученного объекта-потока InputStream. Сам же объект класса InputStream доступен для ParseXML посредством объекта InputStreamReader. Ниже приведен отрывок кода, который это реализует:

HttpConnection hc = (HttpConnection)Connector.open(url);
InputStream is = hc.openInputStream();
Reader reader = new InputStreamReader(is);
XmlParser parser = new XmlParser(reader);

Когда метод класса ParseXML read() обнаруживает элемент, он возвращает объект класса ParseEvent. Этот объект содержит важную информацию, например, тип события (это может быть начало тэга, конец тэга, конец документа, текст или пробельные символы), имя события (фактически - это имя тэга) и текст события (это текст, заключенный в начальный и конечный тэги одного элемента). Как будет показано в нижеследующем листинге, в нашем примере парсер ищет тэги с именем title и description, после этого идет дальше, чтобы получить их содержимое для вывода на экран.

Объект ParseEvent генерирует события (Event) типов Xml.START_TAG, Xml.END_TAG, Xml.END_DOCUMENT, Xml.WHITESPACE и Xml.TEXT, когда он обнаруживает начало тэга, конец тэга, конец документа, пробельные символы и текст, заключенный в тэги, соответственно.


case Xml.START_TAG:
	 // смотрите документацию по API для StartTag для более подробной информации о его доступных методах
	 // "Ловим" Title (заголовок)
	  if ("title".equals(event.getName()))
	  	{
			pe = parser.read();
			title = pe.getText();
		}
	 // "Ловим" Description (описание)
	  if ("description".equals(event.getName()))
	  {
	  		pe = parser.read();
	  		desc = pe.getText();
	  }
		

Следующий листинг содержит полный вариант исходного кода приложения ParseXML.


import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;

// импорты kXML
import org.kxml.*;
import org.kxml.parser.*;
public class ParseXML extends MIDlet implements CommandListener {
	private Command exitCommand;	// Команда выхода из приложения
	private Command displayXML;	// При вызове этой команды, на экран телефона выводятся 
					// заголовки и описания новостей RSS
	private Display display;	// Основной объект Display для этого MIDlet'а

	// Элементы пользовательского интерфейса для отображения заголовков и описаний
	private static TextBox t;
	private static String textBoxString = "";

	// Строка XML
	private String xmlStr = "";
	public ParseXML() {
		 display = Display.getDisplay( this );
		 exitCommand = new Command( "Exit", Command.EXIT, 2 );
		 displayXML  = new Command( "XML", Command.SCREEN, 1 );
		// Формирование XML-строки на основании данных RSS
		StringBuffer xmlString = new StringBuffer();
		xmlString.append("<?xml version=\"1.0\"?>
	<!DOCTYPE rss PUBLIC \"-//Netscape Communications//DTD RSS 0.91//EN\""); 
		xmlString.append("\"http://my.netscape.com/publish/formats/rss-0.91.dtd\">");
		xmlString.append("<rss version=\"0.91\">"); 
		xmlString.append("<channel><title>Meerkat: An Open Wire Service</title>");
		xmlString.append("<link>http://meerkat.oreillynet.com</link>");
		xmlString.append("<description>Meerkat is a Web-based syndicated content
       	          reader based on RSS (\"Rich Site Summary\").
       	          RSS is a fantastic, simple-yet-powerful syndication 
       	          system rapidly gaining momentum.");
		xmlString.append("</description><language>en-us</language>");
		xmlString.append("</channel>");
		xmlString.append("</rss>");
		xmlStr = xmlString.toString();
	}
	public void startApp() {
		// В текстовом поле выводятся заголовок и описание данных из этой XML-строки
		t = new TextBox( "MIDlet XML", "kXML", 256, 0 );
		t.addCommand( exitCommand );
		t.addCommand( displayXML );
		t.setCommandListener( this );
		display.setCurrent( t );
	}
	/**
	 Этот метод (пауза) не определен, поскольку нет никаких фоновых задач и 
	 не нужно заботиться о сохранении данных при закрытии или выходе из MIDlet'а
	*/
	public void pauseApp() { }

	/**
	 Метод destroyApp() должен очистить все то, что не входит в обязанности 
	 cсистемного "сборщика" мусора. В нашем случае, он не делает ничего.
	*/
	public void destroyApp(boolean unconditional) { }

	/*
	 Этим методом определяем обработчики команд при их вызове, включая запрос на выход из
	 приложения. При выходе из приложения, мы выгружаем модуль нашего приложения и оповещаем
	 об этом (notifyDestroyed()) систему.
	*/
	public void commandAction(Command c, Displayable s) {
		if ( c == exitCommand ) {
			destroyApp( false );
			notifyDestroyed();
		} 
		else if ( c == displayXML ) {
			try {
				viewXML();
			}
			catch( Exception e ) {
				e.printStackTrace();
			}
		}
	}

	// Эта функция настраивает парсер kXML и вызывает метод traverse() 
	// для обработки строки XML
	public void viewXML() throws IOException {
		try {
			byte[] xmlByteArray = xmlStr.getBytes();
			ByteArrayInputStream xmlStream = new 
			ByteArrayInputStream( xmlByteArray );
			InputStreamReader xmlReader = new 
			InputStreamReader( xmlStream );
			XmlParser parser = new XmlParser( xmlReader );
			try {
				 traverse( parser, "" );
			}
			catch (Exception exc)
			{
				 exc.printStackTrace();
			}
			return;
		}
		catch ( IOException e ) {
			return ;
		} finally {
			return ;
		}
	}

	/**
	 Обрабатываем XML-данные
	*/
	public static void traverse( XmlParser parser, String indent ) throws Exception
	{
		boolean leave = false;
		String title = new String();
		String desc = new String();
		do {
			ParseEvent event = parser.read ();
			ParseEvent pe;
			switch ( event.getType() ) {
				// Например, <title> 
			case Xml.START_TAG:
				// "Ловим" Title (заголовок)
				if ("title".equals(event.getName())) {
					pe = parser.read();
					title = pe.getText();
				}
				// "Ловим" Description (описание)
				if ("description".equals(event.getName())) {
	  				pe = parser.read();
			  		desc = pe.getText();
				}
				textBoxString = title + " " + desc;
				traverse( parser, "" ) ; // рекурсивный вызов для каждой пары <тэг></тэг>
				break;
				// Например, </title>
			case Xml.END_TAG:
				leave = true;
				break;
			// Например, </rss>
			case Xml.END_DOCUMENT:
				leave = true;
				break;
			// Текст, заключенный между двумя тэгами элемента
			case Xml.TEXT:
				break;
			case Xml.WHITESPACE:
				break;
			default:
			}
	  	} while( !leave );
		t.setString( textBoxString );
	}

	  

На изображении показано приложение ParseXML в действии.

В этой статье мы рассмотрели, каким образом можно, используя J2ME, сочетать мощь технологий Java и XML. Иными словами скомбинировали переносимый код с переносимыми данными. Проектирование J2ME-приложений со встроенными парсерами может оказаться не простой задачей, поскольку устройства, поддерживающие J2ME, обычно ограничены в количестве системных ресурсов. Однако поскольку компактные парсеры, удовлетворяющие потребностям MIDP, становятся все более распространенными, разбор XML-данных в скором времени очень широко распространиться и станет одной из самых обычных возможностей платформы Java на мобильных устройствах.

Ресурсы


Парсер kXML - http://kxml.enhydra.org/software/downloads/
Парсер NanoXML - http://web.wanadoo.be/cyberelf/nanoxml/
Раздел посвященный беспроводным решениям на developerWorks от IBM - http://www-106.ibm.com/developerworks/wireless
J2ME Toolkit от Sun - http://java.sun.com/products/j2mewtoolkit/
Ряд статей по J2ME от Java.sun.com - http://wireless.java.sun.com/midp/articles

Автор: Алексей Литвинюк,
по материалам Soma Ghosh


Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 11

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/books/show2b.php on line 30
Узнай о чем ты на самом деле сейчас думаешь тут.


[an error occurred while processing this directive]



Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 91

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/news/worldnews.php on line 95