Статьи

Android SDK: создайте простой парсер SAX

Парсинг данных из файла XML является очень распространенной целью в мобильных приложениях. Этот учебник предоставит вам практический подход для чтения XML-данных с помощью SAX-парсера. SAX — это сокращение от «Простой API для XML», и это очень мощный инструмент для чтения XML.


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

Одним из недостатков использования парсера SAX является то, что вы должны определить управляемый событиями API, который будет реагировать на каждый элемент при его получении. Построение может занять много времени, но если вы готовы потратить немного больше времени, чтобы сделать все правильно, результат будет стоящим.


XML является средством хранения и транспортировки данных. Одной из основных вещей, которые вам нужно знать для этого урока, является структура документа XML. XML сделан из серии тегов, как и HTML. Примером открывающего тега может быть <example> , а дополнительным закрывающим тегом будет </example> . Между этими тегами мы найдем данные, содержащиеся в примере тега (также называемого элементом). В некоторых случаях у нас могут быть теги с атрибутами, которые нам нужно обработать в нашем парсере SAX. Примером этого в XML может быть <example attr='value'> .


Вам нужно будет создать новый проект в Eclipse. Поскольку мы работаем с XML и будем использовать Интернет для передачи данных, нам необходимо дать приложению разрешение на доступ к Интернету. Для этого вам нужно открыть файл манифеста приложения и добавить эту строку кода внизу, перед закрывающим тегом </ manifest>:

1
<uses-permission android:name=»android.permission.INTERNET»></uses-permission>

Пока вы находитесь в файле манифеста, вы также должны сделать приложение отлаживаемым. Это можно сделать, добавив следующую строку кода в тег приложения:

1
android:debuggable=’true’

Теперь, когда приложение имеет доступ к Интернету и может быть отлажено, мы можем приступить к реализации парсера SAX.


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

Файл main.xml в вашей папке ресурсов должен быть изменен, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?xml version=»1.0″ encoding=»utf-8″?>
<LinearLayout xmlns:android=»http://schemas.android.com/apk/res/android»
    android:layout_width=»fill_parent»
    android:layout_height=»fill_parent»
    android:orientation=»vertical»
    android:id=»@+id/layout»>
 
    <TextView
            android:layout_width=»fill_parent»
            android:layout_height=»wrap_content»
            android:text=»@string/hello»
            android:textSize=»15dp»
android:gravity=»center_horizontal»
            android:id=»@+id/layout_string»/>
 
</LinearLayout>

Обработчик контента — это то, где нам нужно обрабатывать каждое из входящих событий из XML. Таким образом, в основном обработчик контента будет читать XML, пока не достигнет конца.

При достижении открывающего тега, такого как <example> , startElement обработчик startElement . При достижении закрывающих тегов, таких как </example> вызывается закрывающий метод endElement . Когда анализатор SAX достигает закрывающих тегов, он вызывает метод с именем characters который получает весь контент, который находится между открывающим и закрывающим тегами.
У нас есть String, которая называется elementValue , которая имеет значение null. Каждый раз, когда анализатор запускает конечный тег, мы устанавливаем строку elementValue для данных между этими тегами.
Мы также будем использовать логическое значение elementOn. Мы используем это для отслеживания того, куда передается XML, чтобы после завершения чтения тега и извлечения данных мы установили для него значение false, чтобы мы могли прочитать следующий тег в XML.

У нас есть операторы if, чтобы проверить, когда мы достигаем определенного тега, чтобы использовать сеттеры для установки данных в список массивов, чтобы мы могли отобразить их позже.

Ниже приведен пример кода, используемого в обработчике содержимого:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.android.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
 
public class XMLHandler extends DefaultHandler {
 
    String elementValue = null;
    Boolean elementOn = false;
    public static XMLGettersSetters data = null;
 
    public static XMLGettersSetters getXMLData() {
        return data;
    }
 
    public static void setXMLData(XMLGettersSetters data) {
        XMLHandler.data = data;
    }
 
    /**
     * This will be called when the tags of the XML starts.
     **/
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
 
        elementOn = true;
 
        if (localName.equals(«CATALOG»))
        {
            data = new XMLGettersSetters();
        } else if (localName.equals(«CD»)) {
            /**
             * We can get the values of attributes for eg.
             * we can get the value «band».
             *
             * String attributeValue = attributes.getValue(«attr»);
             * data.setAttribute(attributeValue);
             *
             * */
        }
    }
 
    /**
     * This will be called when the tags of the XML end.
     **/
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
 
        elementOn = false;
 
        /**
         * Sets the values after retrieving the values from the XML tags
         * */
        if (localName.equalsIgnoreCase(«title»))
            data.setTitle(elementValue);
        else if (localName.equalsIgnoreCase(«artist»))
            data.setArtist(elementValue);
        else if (localName.equalsIgnoreCase(«country»))
            data.setCountry(elementValue);
        else if (localName.equalsIgnoreCase(«company»))
            data.setCompany(elementValue);
        else if (localName.equalsIgnoreCase(«price»))
            data.setPrice(elementValue);
        else if (localName.equalsIgnoreCase(«year»))
            data.setYear(elementValue);
    }
 
    /**
     * This is called to get the tags value
     **/
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
 
        if (elementOn) {
            elementValue = new String(ch, start, length);
            elementOn = false;
        }
 
    }
 
}

В startElement я включил комментарий, чтобы показать, как получить атрибут открытого тега.


Это очень простой класс, который содержит arraylists, getter и setters. Здесь списки массивов устанавливаются из класса обработчика содержимого путем вызова их соответствующих методов установки.

В этом примере это просто, потому что мы в основном извлекаем строковые типы. Однако в других XML-файлах вам может потребоваться получить другие типы, такие как дата или URL, и вам придется вносить коррективы по мере необходимости. Возьмем, к примеру, дату: вам, возможно, придется использовать форматер даты, чтобы правильно отформатировать дату, прежде чем ее установить.

В каждом из методов установки я добавил журналы, как показано ниже:

1
Log.i(‘This is the value:’, example);

Это очень полезно, поскольку вы можете использовать Logcat, который находится в перспективе DDMS, чтобы отслеживать все данные, которые вы извлекаете для XML. Большим преимуществом этого является то, что в случае сбоя вашего кода вы будете точно знать, в каком теге происходит сбой анализатора, и сможете внести необходимые коррективы.

Ниже приведен фрагмент кода из класса методов получения и установки, показывающий только один из методов получения и установки:

1
2
3
4
5
6
7
8
9
public class XMLGettersSetters {
private ArrayList<String> company = new ArrayList<String>();
    public ArrayList<String> getCompany() {
        return company;
    }
    public void setCompany(String company) {
        this.company.add(company);
        Log.i(«This is the company:», company);
    }

Ниже изображение Logcat, показывающее все полученные данные.

Описание

В упражнении нам нужно будет создать экземпляр синтаксического анализатора SAX. Нам также нужно создать обработчик для каждого из тегов XML. У нас также есть URL-адрес XML, который нам нужно передать в обработчик. Вот код, используемый для реализации этого:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
try {
    /**
    * Create a new instance of the SAX parser
    **/
    SAXParserFactory saxPF = SAXParserFactory.newInstance();
    SAXParser saxP = saxPF.newSAXParser();
    XMLReader xmlR = saxP.getXMLReader();
 
         
    URL url = new URL(«http://www.xmlfiles.com/examples/cd_catalog.xml»);
         
    /**
    * Create the Handler to handle each of the XML tags.
    **/
    XMLHandler myXMLHandler = new XMLHandler();
    xmlR.setContentHandler(myXMLHandler);
    xmlR.parse(new InputSource(url.openStream()));
         
} catch (Exception e) {
    System.out.println(e);
}

Последний шаг — отобразить данные в Activity. Для каждой категории данных нам нужно создать отдельный массив TextView. Например:

1
TextView example[];

Сделав это, мы сможем добавить все полученные данные в эти TextViews. Нам нужно сделать длину TextView равной размеру TextView, следующая строка кода установит длину TextView равной размеру массива TextView:

1
example = new TextView[data.getExample().size()];

Нам нужно получить макет Activity, чтобы установить все TextViews, которые для него созданы программно. Используя представление, мы можем сделать это просто. Ниже приведена строка кода, которая нам нужна:

1
View layout = findViewById(R.id.layout);

Теперь, когда у нас есть длина TextView, мы можем просто запустить цикл for, чтобы добавить данные в эти TextView. Цикл for завершится, когда будет достигнут конец массива TextView.

Вот код, используемый для реализации цикла for, чтобы установить данные для TextViews, а затем установить TextViews для макета:

01
02
03
04
05
06
07
08
09
10
11
for (int i = 0; i < data.getExample().size(); i++) {
             
            example[i] = new TextView(this);
            example[i].setText(«Example= «+data.getExample ().get(i));
             
            example2[i] = new TextView(this);
            example2[i].setText(«Example2 =»+data.get Example2().get(i));
 
            ((ViewGroup) layout).addView(example[i]);
            ((ViewGroup) layout).addView(example2[i]);
        }

Последняя строка кода будет использоваться для установки макета:

1
setContentView(layout);

Теперь, когда все настроено правильно, вы можете запустить свое приложение. Результаты должны выглядеть как на картинке ниже. Если вы получите ошибку, наиболее вероятной причиной будет неправильная обработка XML. Лучший способ приблизиться к отладке, используя Logcat.

Описание