اللغة الترميزية القابلة للامتداد (XML) هي مجموعة من القواعد لتشفير المستندات في ويمكن للآلة قراءته. XML هو تنسيق شائع لمشاركة البيانات على الإنترنت.
المواقع الإلكترونية التي تعدِّل محتواها بشكل متكرر، مثل المواقع الإخبارية أو المدونات وتوفر خلاصة XML حتى تتمكن البرامج الخارجية من مواكبة المحتوى التغييرات. يعد تحميل بيانات XML وتحليلها مهمة شائعة بالنسبة إلى الأجهزة المتصلة بالشبكة التطبيقات. يوضح هذا الموضوع كيفية تحليل مستندات XML واستخدام بياناتها.
لمزيد من المعلومات حول إنشاء محتوى مستند إلى الويب في تطبيق Android، يُرجى الاطّلاع على المحتوى المستنِد إلى الويب:
اختيار محلل لغوي
نقترح استخدام السمة XmlPullParser
، وهي نظام فعّال
يمكن المحافظة عليها لتحليل XML على Android. يحتوي Android على اثنين
واستخدامات هذه الواجهة:
KXmlParser
، باستخدامXmlPullParserFactory.newPullParser()
ExpatPullParser
: يتم استخدامXml.newPullParser()
لا بأس في أي من الخيارين. تشير رسالة الأشكال البيانية
المثال في هذا القسم يستخدم ExpatPullParser
Xml.newPullParser()
تحليل الخلاصة
الخطوة الأولى في تحليل الخلاصة هي تحديد الحقول التي تهمّك. يستخرج المحلل اللغوي بيانات هذه الحقول ويتجاهل الباقي.
يمكنك الاطّلاع على المقتطف التالي من خلاصة محللة في نموذج التطبيق. على كل
تظهر المشاركة على StackOverflow.com في
الخلاصة كعلامة entry
تحتوي على العديد من العلامات المدمَجة:
<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" ..."> <title type="text">newest questions tagged android - Stack Overflow</title> ... <entry> ... </entry> <entry> <id>http://stackoverflow.com/q/9439999</id> <re:rank scheme="http://stackoverflow.com">0</re:rank> <title type="text">Where is my data file?</title> <category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="android"/> <category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="file"/> <author> <name>cliff2310</name> <uri>http://stackoverflow.com/users/1128925</uri> </author> <link rel="alternate" href="http://stackoverflow.com/questions/9439999/where-is-my-data-file" /> <published>2012-02-25T00:30:54Z</published> <updated>2012-02-25T00:30:54Z</updated> <summary type="html"> <p>I have an Application that requires a data file...</p> </summary> </entry> <entry> ... </entry> ... </feed>
نموذج التطبيق
يستخرج البيانات الخاصة بالعلامة entry
وعلاماتها المدمجة.
title
وlink
وsummary
إنشاء مثيل للمحلل اللغوي
الخطوة التالية في تحليل الخلاصة هي
إنشاء مثيل للمحلل وبدء عملية التحليل. هذا المقتطف
تؤدي هذه السياسة إلى إعداد محلّل لغوي كي لا يعالج مساحات الاسم ويستخدم InputStream
المُقدّم كإدخاله. فهي تبدأ عملية التحليل باستدعاء
nextTag()
ويستدعي
readFeed()
: تستخرج البيانات التي يستخدمها التطبيق وتعالجها.
مهتم بـ:
Kotlin
// We don't use namespaces. private val ns: String? = null class StackOverflowXmlParser { @Throws(XmlPullParserException::class, IOException::class) fun parse(inputStream: InputStream): List<*> { inputStream.use { inputStream -> val parser: XmlPullParser = Xml.newPullParser() parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false) parser.setInput(inputStream, null) parser.nextTag() return readFeed(parser) } } ... }
Java
public class StackOverflowXmlParser { // We don't use namespaces. private static final String ns = null; public List parse(InputStream in) throws XmlPullParserException, IOException { try { XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(in, null); parser.nextTag(); return readFeed(parser); } finally { in.close(); } } ... }
قراءة الخلاصة
تؤدي الطريقة readFeed()
العمل الفعلي لمعالجة
الخلاصة. يبحث عن عناصر تحمل علامة "إدخال" كنقطة انطلاق للتكرار
جارٍ معالجة الخلاصة. وإذا لم تكن العلامة هي علامة entry
، ستتخطّاها. بمجرد أن تكتمل
معالجة الخلاصة بشكل متكرر، ويعرض readFeed()
List
التي تحتوي على الإدخالات (بما في ذلك أعضاء البيانات المتداخلة) التي
المستخرجة من الخلاصة. يتم بعد ذلك إرجاع قيمة "List
" هذه من خلال
المحلل اللغوي.
Kotlin
@Throws(XmlPullParserException::class, IOException::class) private fun readFeed(parser: XmlPullParser): List<Entry> { val entries = mutableListOf<Entry>() parser.require(XmlPullParser.START_TAG, ns, "feed") while (parser.next() != XmlPullParser.END_TAG) { if (parser.eventType != XmlPullParser.START_TAG) { continue } // Starts by looking for the entry tag. if (parser.name == "entry") { entries.add(readEntry(parser)) } else { skip(parser) } } return entries }
Java
private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException { List entries = new ArrayList(); parser.require(XmlPullParser.START_TAG, ns, "feed"); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } String name = parser.getName(); // Starts by looking for the entry tag. if (name.equals("entry")) { entries.add(readEntry(parser)); } else { skip(parser); } } return entries; }
تحليل XML
في ما يلي خطوات تحليل خلاصة XML:
- كما هو موضح في قسم تحليل الخلاصة، حدِّد العلامات التي تريد تضمينها في تطبيقك. هذا النمط
يستخلص المثال بيانات العلامة
entry
وعلاماتها المتداخلة:title
وlink
وsummary
- أنشئ الطرق التالية:
- "قراءة" لكل علامة تريد تضمينها، مثل
"
readEntry()
" وreadTitle()
" يقرأ المحلل اللغوي العلامات من مصدر البيانات المُدخَل. عندما تواجه علامة مسماة، في هذا المثال،entry
،title
،link
أوsummary
، فإنها تستدعي الطريقة المناسبة لهذه العلامة. وبخلاف ذلك، يتخطى العلامة العلامة. - طرق استخراج البيانات لكل نوع مختلف من العلامات وتعزيز
محلل لغوي إلى العلامة التالية. في هذا المثال، تكون الطرق ذات الصلة كما يلي:
- بالنسبة إلى العلامتين
title
وsummary
، يستدعي المحلل اللغويreadText()
تستخرج هذه الطريقة بيانات هذه العلامات عن طريق استدعاءparser.getText()
- بالنسبة إلى العلامة
link
، يستخرج المحلل اللغوي بيانات الروابط أولاً ما إذا كان الرابط هو نوع المحتوى التي يهتم بها. بعد ذلك، يستخدمparser.getAttributeValue()
لإجراء ما يلي: لاستخراج قيمة الرابط - بالنسبة إلى العلامة
entry
، يستدعي المحلل اللغويreadEntry()
. تُحلِّل هذه الطريقة العلامات المُدمَجة للإدخال وتعرضEntry
يحتوي على أعضاء البياناتtitle
وlink
وsummary
- بالنسبة إلى العلامتين
- طريقة
skip()
مساعِدة متكررة. لمزيد من المناقشة حول هذا الموضوع، يُرجى الاطّلاع على تخطّي العلامات التي لا تهمّك.
- "قراءة" لكل علامة تريد تضمينها، مثل
"
يعرض هذا المقتطف طريقة تحليل المحلل للإدخالات والعناوين والروابط والملخصات.
Kotlin
data class Entry(val title: String?, val summary: String?, val link: String?) // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off // to their respective "read" methods for processing. Otherwise, skips the tag. @Throws(XmlPullParserException::class, IOException::class) private fun readEntry(parser: XmlPullParser): Entry { parser.require(XmlPullParser.START_TAG, ns, "entry") var title: String? = null var summary: String? = null var link: String? = null while (parser.next() != XmlPullParser.END_TAG) { if (parser.eventType != XmlPullParser.START_TAG) { continue } when (parser.name) { "title" -> title = readTitle(parser) "summary" -> summary = readSummary(parser) "link" -> link = readLink(parser) else -> skip(parser) } } return Entry(title, summary, link) } // Processes title tags in the feed. @Throws(IOException::class, XmlPullParserException::class) private fun readTitle(parser: XmlPullParser): String { parser.require(XmlPullParser.START_TAG, ns, "title") val title = readText(parser) parser.require(XmlPullParser.END_TAG, ns, "title") return title } // Processes link tags in the feed. @Throws(IOException::class, XmlPullParserException::class) private fun readLink(parser: XmlPullParser): String { var link = "" parser.require(XmlPullParser.START_TAG, ns, "link") val tag = parser.name val relType = parser.getAttributeValue(null, "rel") if (tag == "link") { if (relType == "alternate") { link = parser.getAttributeValue(null, "href") parser.nextTag() } } parser.require(XmlPullParser.END_TAG, ns, "link") return link } // Processes summary tags in the feed. @Throws(IOException::class, XmlPullParserException::class) private fun readSummary(parser: XmlPullParser): String { parser.require(XmlPullParser.START_TAG, ns, "summary") val summary = readText(parser) parser.require(XmlPullParser.END_TAG, ns, "summary") return summary } // For the tags title and summary, extracts their text values. @Throws(IOException::class, XmlPullParserException::class) private fun readText(parser: XmlPullParser): String { var result = "" if (parser.next() == XmlPullParser.TEXT) { result = parser.text parser.nextTag() } return result } ...
Java
public static class Entry { public final String title; public final String link; public final String summary; private Entry(String title, String summary, String link) { this.title = title; this.summary = summary; this.link = link; } } // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off // to their respective "read" methods for processing. Otherwise, skips the tag. private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException { parser.require(XmlPullParser.START_TAG, ns, "entry"); String title = null; String summary = null; String link = null; while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } String name = parser.getName(); if (name.equals("title")) { title = readTitle(parser); } else if (name.equals("summary")) { summary = readSummary(parser); } else if (name.equals("link")) { link = readLink(parser); } else { skip(parser); } } return new Entry(title, summary, link); } // Processes title tags in the feed. private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException { parser.require(XmlPullParser.START_TAG, ns, "title"); String title = readText(parser); parser.require(XmlPullParser.END_TAG, ns, "title"); return title; } // Processes link tags in the feed. private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException { String link = ""; parser.require(XmlPullParser.START_TAG, ns, "link"); String tag = parser.getName(); String relType = parser.getAttributeValue(null, "rel"); if (tag.equals("link")) { if (relType.equals("alternate")){ link = parser.getAttributeValue(null, "href"); parser.nextTag(); } } parser.require(XmlPullParser.END_TAG, ns, "link"); return link; } // Processes summary tags in the feed. private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException { parser.require(XmlPullParser.START_TAG, ns, "summary"); String summary = readText(parser); parser.require(XmlPullParser.END_TAG, ns, "summary"); return summary; } // For the tags title and summary, extracts their text values. private String readText(XmlPullParser parser) throws IOException, XmlPullParserException { String result = ""; if (parser.next() == XmlPullParser.TEXT) { result = parser.getText(); parser.nextTag(); } return result; } ... }
تخطي العلامات التي لا تهمّك
يحتاج المحلل اللغوي إلى تخطي العلامات التي لا يهتم بها. ها هي طريقة skip()
للمحلل اللغوي:
Kotlin
@Throws(XmlPullParserException::class, IOException::class) private fun skip(parser: XmlPullParser) { if (parser.eventType != XmlPullParser.START_TAG) { throw IllegalStateException() } var depth = 1 while (depth != 0) { when (parser.next()) { XmlPullParser.END_TAG -> depth-- XmlPullParser.START_TAG -> depth++ } } }
Java
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException { if (parser.getEventType() != XmlPullParser.START_TAG) { throw new IllegalStateException(); } int depth = 1; while (depth != 0) { switch (parser.next()) { case XmlPullParser.END_TAG: depth--; break; case XmlPullParser.START_TAG: depth++; break; } } }
إليك كيفية العمل:
- يضع استثناءً إذا لم يكن الحدث الحالي
START_TAG
- يستهلك هذا الحقل
START_TAG
وجميع الأحداث بما يصل إلىEND_TAG
المطابقة. - ويتتبّع النظام عمق التداخل للتأكّد من أنّه يتوقف عند
END_TAG
الصحيح وليس عند أوّل علامة تظهر بعد علامةSTART_TAG
الأصلية.
وبالتالي، إذا كان العنصر الحالي يتضمن عناصر متداخلة، فإن قيمة
لن تكون قيمة depth
بقيمة 0 حتى يستنفد المحلل اللغوي جميع الأحداث بين
START_TAG
الأصلي وEND_TAG
المطابق له. بالنسبة
لنفترض مثلاً أنّ المحلل يتخطّى العنصر <author>
والذي يتكون من عنصرين مدمجين، <name>
<uri>
:
- في المرة الأولى التي تمر فيها حلقة
while
، يستخدم المحلل اللغوي العلامة التالية المواجهات بعد<author>
هوSTART_TAG
<name>
تزيد قيمةdepth
إلى 2- - في المرة الثانية خلال التكرار الحلقي
while
، يستخدم المحلل اللغوي العلامة التالية هيEND_TAG
</name>
. القيمة لـdepth
إنقاص إلى 1. - في المرة الثالثة خلال التكرار الحلقي
while
، سينتقل المحلل اللغوي للعلامة التالية هيSTART_TAG
<uri>
. القيمة لـdepth
زيادات إلى 2. - في المرة الرابعة خلال التكرار الحلقي
while
، يستخدم المحلل اللغوي العلامة التالية هيEND_TAG
</uri>
. قيمةdepth
ينقص إلى 1. - المرة الخامسة والأخيرة خلال حلقة
while
، هي المرة التالية العلامة التي يصادفها المحلل اللغوي هي علامةEND_TAG
</author>
تقل قيمةdepth
إلى 0، ما يشير إلى أنّ العنصر<author>
تم بنجاح. تم تخطيه.
استهلاك بيانات XML
يجلب مثال التطبيق خلاصة XML ويحلّلها بشكل غير متزامن. سيؤدي هذا إلى إزالة سلسلة التعليمات من واجهة المستخدم الرئيسية. فعندما
اكتمال المعالجة، يقوم التطبيق بتحديث واجهة المستخدم في نشاطه الرئيسي،
NetworkActivity
في المقتطف التالي، تؤدي طريقة loadPage()
ما يلي:
- لإعداد متغيّر سلسلة باستخدام عنوان URL لخلاصة XML.
- لاستدعاء الإجراء
downloadXml(url)
، إذا كانت إعدادات المستخدم والشبكة الاتصال يسمح بذلك. تقوم هذه الطريقة بتنزيل الخلاصة وتحليلها وعرض نتيجة سلسلة لتكون المعروض في واجهة المستخدم.
Kotlin
class NetworkActivity : Activity() { companion object { const val WIFI = "Wi-Fi" const val ANY = "Any" const val SO_URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest" // Whether there is a Wi-Fi connection. private var wifiConnected = false // Whether there is a mobile connection. private var mobileConnected = false // Whether the display should be refreshed. var refreshDisplay = true // The user's current network preference setting. var sPref: String? = null } ... // Asynchronously downloads the XML feed from stackoverflow.com. fun loadPage() { if (sPref.equals(ANY) && (wifiConnected || mobileConnected)) { downloadXml(SO_URL) } else if (sPref.equals(WIFI) && wifiConnected) { downloadXml(SO_URL) } else { // Show error. } } ... }
Java
public class NetworkActivity extends Activity { public static final String WIFI = "Wi-Fi"; public static final String ANY = "Any"; private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest"; // Whether there is a Wi-Fi connection. private static boolean wifiConnected = false; // Whether there is a mobile connection. private static boolean mobileConnected = false; // Whether the display should be refreshed. public static boolean refreshDisplay = true; public static String sPref = null; ... // Asynchronously downloads the XML feed from stackoverflow.com. public void loadPage() { if((sPref.equals(ANY)) && (wifiConnected || mobileConnected)) { downloadXml(URL); } else if ((sPref.equals(WIFI)) && (wifiConnected)) { downloadXml(URL); } else { // Show error. } }
تستدعي الطريقة downloadXml
الطرق التالية في Kotlin:
lifecycleScope.launch(Dispatchers.IO)
، التي تستخدم الكوروتينات بلغة Kotlin تشغيل الطريقةloadXmlFromNetwork()
في سلسلة محادثات IO. يمرر عنوان URL للخلاصة على أنه . الطريقة التي تجلبها الطريقةloadXmlFromNetwork()
وتعالجها الخلاصة. عند الانتهاء، تُمرر سلسلة نتيجة.- تستخدم الدالة
withContext(Dispatchers.Main)
، التي تستخدم الكوروتينات في لغة Kotlin للعودة إلى سلسلة التعليمات الرئيسية، وإرجاع السلسلة، ويعرضها في واجهة المستخدم.
في لغة برمجة Java، تكون العملية على النحو التالي:
- يتم تنفيذ
Executor
. الطريقةloadXmlFromNetwork()
على سلسلة محادثات في الخلفية. يمرر عنوان URL للخلاصة على أنه . الطريقة التي تجلبها الطريقةloadXmlFromNetwork()
وتعالجها الخلاصة. عند الانتهاء، تُمرر سلسلة نتيجة. Handler
الاتصال بـpost
للعودة إلى سلسلة التعليمات الرئيسية وإرجاع السلسلة، ويعرضها في واجهة المستخدم.
Kotlin
// Implementation of Kotlin coroutines used to download XML feed from stackoverflow.com. private fun downloadXml(vararg urls: String) { var result: String? = null lifecycleScope.launch(Dispatchers.IO) { result = try { loadXmlFromNetwork(urls[0]) } catch (e: IOException) { resources.getString(R.string.connection_error) } catch (e: XmlPullParserException) { resources.getString(R.string.xml_error) } withContext(Dispatchers.Main) { setContentView(R.layout.main) // Displays the HTML string in the UI via a WebView. findViewById<WebView>(R.id.webview)?.apply { loadData(result?: "", "text/html", null) } } } }
Java
// Implementation of Executor and Handler used to download XML feed asynchronously from stackoverflow.com. private void downloadXml(String... urls) { ExecutorService executor = Executors.newSingleThreadExecutor(); Handler handler = new Handler(Looper.getMainLooper()); executor.execute(() -> { String result; try { result = loadXmlFromNetwork(urls[0]); } catch (IOException e) { result = getResources().getString(R.string.connection_error); } catch (XmlPullParserException e) { result = getResources().getString(R.string.xml_error); } String finalResult = result; handler.post(() -> { setContentView(R.layout.main); // Displays the HTML string in the UI via a WebView. WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadData(finalResult, "text/html", null); }); }); }
طريقة loadXmlFromNetwork()
التي تم استدعاؤها من
يتم عرض downloadXml
في المقتطف التالي. ويؤديها إلى ما يلي:
- ينشئ مثيلاً لـ
StackOverflowXmlParser
. كما أنه ينشئ متغيراتList
من إجماليEntry
عنصرًا (entries
) ولـtitle
وurl
وsummary
، للاحتفاظ القيم المستخرجة من خلاصة XML لهذه الحقول. - استدعاء
downloadUrl()
، الذي يجلب الخلاصة ويعرضها على النحو التاليInputStream
. - تستخدم
StackOverflowXmlParser
لتحليلInputStream
. يملأStackOverflowXmlParser
List
منentries
مع بيانات من الخلاصة. - معالجة
List
لـentries
وتدمج بيانات الخلاصة مع ترميز HTML - إرجاع سلسلة HTML معروضة في النشاط الرئيسي واجهة مستخدم
Kotlin
// Uploads XML from stackoverflow.com, parses it, and combines it with // HTML markup. Returns HTML string. @Throws(XmlPullParserException::class, IOException::class) private fun loadXmlFromNetwork(urlString: String): String { // Checks whether the user set the preference to include summary text. val pref: Boolean = PreferenceManager.getDefaultSharedPreferences(this)?.run { getBoolean("summaryPref", false) } ?: false val entries: List<Entry> = downloadUrl(urlString)?.use { stream -> // Instantiates the parser. StackOverflowXmlParser().parse(stream) } ?: emptyList() return StringBuilder().apply { append("<h3>${resources.getString(R.string.page_title)}</h3>") append("<em>${resources.getString(R.string.updated)} ") append("${formatter.format(rightNow.time)}</em>") // StackOverflowXmlParser returns a List (called "entries") of Entry objects. // Each Entry object represents a single post in the XML feed. // This section processes the entries list to combine each entry with HTML markup. // Each entry is displayed in the UI as a link that optionally includes // a text summary. entries.forEach { entry -> append("<p><a href='") append(entry.link) append("'>" + entry.title + "</a></p>") // If the user set the preference to include summary text, // adds it to the display. if (pref) { append(entry.summary) } } }.toString() } // Given a string representation of a URL, sets up a connection and gets // an input stream. @Throws(IOException::class) private fun downloadUrl(urlString: String): InputStream? { val url = URL(urlString) return (url.openConnection() as? HttpURLConnection)?.run { readTimeout = 10000 connectTimeout = 15000 requestMethod = "GET" doInput = true // Starts the query. connect() inputStream } }
Java
// Uploads XML from stackoverflow.com, parses it, and combines it with // HTML markup. Returns HTML string. private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException { InputStream stream = null; // Instantiates the parser. StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser(); List<Entry> entries = null; String title = null; String url = null; String summary = null; Calendar rightNow = Calendar.getInstance(); DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa"); // Checks whether the user set the preference to include summary text. SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); boolean pref = sharedPrefs.getBoolean("summaryPref", false); StringBuilder htmlString = new StringBuilder(); htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>"); htmlString.append("<em>" + getResources().getString(R.string.updated) + " " + formatter.format(rightNow.getTime()) + "</em>"); try { stream = downloadUrl(urlString); entries = stackOverflowXmlParser.parse(stream); // Makes sure that the InputStream is closed after the app is // finished using it. } finally { if (stream != null) { stream.close(); } } // StackOverflowXmlParser returns a List (called "entries") of Entry objects. // Each Entry object represents a single post in the XML feed. // This section processes the entries list to combine each entry with HTML markup. // Each entry is displayed in the UI as a link that optionally includes // a text summary. for (Entry entry : entries) { htmlString.append("<p><a href='"); htmlString.append(entry.link); htmlString.append("'>" + entry.title + "</a></p>"); // If the user set the preference to include summary text, // adds it to the display. if (pref) { htmlString.append(entry.summary); } } return htmlString.toString(); } // Given a string representation of a URL, sets up a connection and gets // an input stream. private InputStream downloadUrl(String urlString) throws IOException { URL url = new URL(urlString); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(10000 /* milliseconds */); conn.setConnectTimeout(15000 /* milliseconds */); conn.setRequestMethod("GET"); conn.setDoInput(true); // Starts the query. conn.connect(); return conn.getInputStream(); }