Рассмотрим получение данных в формате xml по сети. Допустим, на некотором сайте https://example.com находится файл users.xml со следующим содержимым:
<?xml version="1.0" encoding="utf-8"?>
<users>
<user>
<name>Tom</name>
<age>36</age>
</user>
<user>
<name>Alice</name>
<age>32</age>
</user>
<user>
<name>Bob</name>
<age>28</age>
</user>
</users>
То есть сам файл доступен по адресу https://example.com/users.xml. Но это необязательно должен быть именно файл, это может быть любой ресурс, который динамически генерирует данные в xml.
Возьмем стандартный проект Android и вначале определим в нем класс User, который будет представлять загружаемые данные:
package com.example.xmlapp;
public class User {
private String name;
private String age;
public String getName(){
return name;
}
public String getAge(){
return age;
}
public void setName(String name){
this.name = name;
}
public void setAge(String age){
this.age = age;
}
public String toString(){
return "User: " + name + " - " + age;
}
}
Далее определим класс UserXmlParser:
package com.example.xmlapp;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.util.ArrayList;
import java.io.StringReader;
public class UserXmlParser {
private ArrayList<User> users;
public UserXmlParser(){
users = new ArrayList<>();
}
public ArrayList<User> getUsers(){
return users;
}
public boolean parse(String xmlData){
boolean status = true;
User currentUser = null;
boolean inEntry = false;
String textValue = "";
try{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new StringReader(xmlData));
int eventType = xpp.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT){
String tagName = xpp.getName();
switch (eventType){
case XmlPullParser.START_TAG:
if("user".equalsIgnoreCase(tagName)){
inEntry = true;
currentUser = new User();
}
break;
case XmlPullParser.TEXT:
textValue = xpp.getText();
break;
case XmlPullParser.END_TAG:
if(inEntry){
if("user".equalsIgnoreCase(tagName)){
users.add(currentUser);
inEntry = false;
} else if("name".equalsIgnoreCase(tagName)){
currentUser.setName(textValue);
} else if("age".equalsIgnoreCase(tagName)){
currentUser.setAge(textValue);
}
}
break;
default:
}
eventType = xpp.next();
}
}
catch (Exception e){
status = false;
e.printStackTrace();
}
return status;
}
}
То есть в итоге получится следующий проект:
Для парсинга xml здесь используется класс XmlPullParser, который уже рассматривался в прошлой теме. Единственное отличие заключается в том, что для создания объекта этого класса применяется класс XmlPullParserFactory:
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xpp = factory.newPullParser();
Для работы определим простейший визуальный интефейс в файле activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/contentView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/usersList"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ListView
android:id="@+id/usersList"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/contentView" />
</androidx.constraintlayout.widget.ConstraintLayout>
Здесь определен элемент TextView для отображения некоторой дополнительной информации о состоянии загрузки файла и элемент ListView для отображения загруженных объектов.
Далее изменим класс MainActivity:
package com.example.xmlapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView usersList = findViewById(R.id.usersList);
TextView contentView = findViewById(R.id.contentView);
contentView.setText("Загрузка...");
new Thread(new Runnable() {
public void run() {
try{
String content = download("https://example.com/users.xml");
usersList.post(new Runnable() {
public void run() {
UserXmlParser parser = new UserXmlParser();
if(parser.parse(content))
{
ArrayAdapter<User> adapter = new ArrayAdapter(getBaseContext(),
android.R.layout.simple_list_item_1, parser.getUsers());
usersList.setAdapter(adapter);
contentView.setText("Загруженно объектов: " + adapter.getCount());
}
}
});
}
catch (IOException ex){
contentView.post(new Runnable() {
public void run() {
contentView.setText("Ошибка: " + ex.getMessage());
}
});
}
}
}).start();
}
private String download(String urlPath) throws IOException{
StringBuilder xmlResult = new StringBuilder();
BufferedReader reader = null;
InputStream stream = null;
HttpsURLConnection connection = null;
try {
URL url = new URL(urlPath);
connection = (HttpsURLConnection) url.openConnection();
stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
String line;
while ((line=reader.readLine()) != null) {
xmlResult.append(line);
}
return xmlResult.toString();
} finally {
if (reader != null) {
reader.close();
}
if (stream != null) {
stream.close();
}
if (connection != null) {
connection.disconnect();
}
}
}
}
При создании MainActivity будет запускаться дополнительный поток, который вызывает метод download(). Этот метод с помощью
класса HttpsURLConnection загужает файл users.xml и возвращает его содержимое в виде строки (Если необходимо загрузить файл xml по протоколу http, то
вместо применяется класса HttpsURLConnection класс java.net.HttpURLConnection).
String content = download("https://example.com/users.xml");
Затем загруженное содержимое передается в метод parse(), класса UserXmlParser, который формирует список объектов.
UserXmlParser parser = new UserXmlParser();
if(parser.parse(content)){
//...................
Затем загруженный список передается в адаптер ArrayAdapter, а через него в ListView для отображения на экране устройства:
ArrayAdapter<User> adapter = new ArrayAdapter(getBaseContext(), android.R.layout.simple_list_item_1, parser.getUsers()); usersList.setAdapter(adapter);
В завершении надо добавить в файл манифеста AndroidManifest.xml разрешения на взаимодействие с сетью:
<uses-permission android:name="android.permission.INTERNET"/>
И после запуска приложения в окне Logcat мы увидим полученные с сервера данные: