XML ডেটা পার্স করুন

এক্সটেনসিবল মার্কআপ ল্যাঙ্গুয়েজ (XML) হল মেশিনের ক্ষেত্রে গ্রহণযোগ্য ফর্মে ডকুমেন্ট এনকোড করার জন্য নিয়মের সেট। ইন্টারনেটে ডেটা শেয়ার করার জন্য XML একটি জনপ্রিয় ফর্ম্যাট।

যেসব ওয়েবসাইট প্রায়শই তাদের কন্টেন্ট আপডেট করে, যেমন খবরের সাইট বা ব্লগ, সেগুলি প্রায়ই XML ফিড প্রদান করে যাতে এক্সটার্নাল প্রোগ্রাম কন্টেন্টের পরিবর্তন সম্পর্কে অবগত থাকতে পারে। নেটওয়ার্ক-কানেক্টেড অ্যাপের ক্ষেত্রে XML ডেটা আপলোড ও পার্স করা একটি সাধারণ কাজ। এই বিষয়ে XML ডকুমেন্ট কীভাবে পার্স করতে হয় এবং তার ডেটা কীভাবে ব্যবহার করতে হয় তা ব্যাখ্যা করা হয়েছে।

আপনার Android অ্যাপে ওয়েব-ভিত্তিক কন্টেন্ট তৈরি করার ব্যাপারে আরও জানতে, ওয়েব-ভিত্তিক কন্টেন্ট দেখুন।

পার্সার বেছে নিন

আমরা XmlPullParser সাজেস্ট করি, যা Android-এ XML পার্স করার একটি দক্ষ এবং রক্ষণাবেক্ষণযোগ্য উপায়। Android-এ এই ইন্টারফেসের দুটি ইমপ্লিমেন্টেশন আছে:

যেকোনও একটি বেছে নিলেই হবে। এই বিভাগের উদাহরণে 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)
        }
    }
 ...
}

জাভা

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
}

জাভা

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 ফিড পার্স করার ধাপগুলি নিচে দেওয়া হল:

  1. ফিড বিশ্লেষণ করুন বিভাগে যেমন বর্ণনা করা হয়েছে, আপনার অ্যাপে যে ট্যাগগুলি অন্তর্ভুক্ত করতে চান সেগুলি শনাক্ত করুন। এই উদাহরণটি entry ট্যাগ এবং এর নেস্টেড ট্যাগগুলির জন্য ডেটা এক্সট্র্যাক্ট করে: title, link এবং summary।
  2. নিম্নলিখিত পদ্ধতিগুলি তৈরি করুন:

    • আপনি অন্তর্ভুক্ত করতে চান এমন প্রতিটি ট্যাগের জন্য একটি "রিড" পদ্ধতি, যেমন readEntry() এবং readTitle()। পার্সার ইনপুট স্ট্রিম থেকে ট্যাগ পড়ে। এই উদাহরণে, entry, title, link বা summary নামের ট্যাগ পেলে, এটি সেই ট্যাগের জন্য উপযুক্ত পদ্ধতি কল করে। অন্যথায়, এটি ট্যাগটি এড়িয়ে যায়।
    • প্রতিটি ভিন্ন ধরনের ট্যাগের জন্য ডেটা এক্সট্র্যাক্ট করার পদ্ধতি এবং পার্সারকে পরবর্তী ট্যাগে নিয়ে যাওয়া। এই উদাহরণে, প্রাসঙ্গিক পদ্ধতিগুলি নিম্নরূপ:
      • title এবং summary ট্যাগের জন্য, পার্সার readText() কল করে। এই পদ্ধতি parser.getText()-কে কল করে এইসব ট্যাগের জন্য ডেটা এক্সট্র্যাক্ট করে।
      • link ট্যাগের জন্য, পার্সার প্রথমে লিঙ্কটি তার আগ্রহের ধরনের কিনা তা নির্ধারণ করে লিঙ্কের জন্য ডেটা এক্সট্র্যাক্ট করে। তারপর এটি parser.getAttributeValue() ব্যবহার করে লিঙ্কের ভ্যালু এক্সট্র্যাক্ট করে।
      • entry ট্যাগের জন্য, পার্সার readEntry() কল করে। এই পদ্ধতি এন্ট্রির নেস্টেড ট্যাগ পার্স করে এবং title, link ও summary ডেটা মেম্বার সহ একটি Entry অবজেক্ট রিটার্ন করে।
    • একটি সহায়ক 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
}
...

জাভা

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++
        }
    }
}

জাভা

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-এর পরে প্রথম যে ট্যাগটি পায় সেখানে না থামে।

তাই, বর্তমান এলিমেন্টে নেস্টেড এলিমেন্ট থাকলে, পার্সার আসল START_TAG এবং তার সাথে ম্যাচ করা END_TAG-এর মধ্যে সব ইভেন্ট ব্যবহার না করা পর্যন্ত depth-এর মান ০ হবে না। যেমন, পার্সার কীভাবে <author> এলিমেন্ট এড়িয়ে যায় তা বিবেচনা করুন, এতে ২টি নেস্টেড এলিমেন্ট আছে, <name> এবং <uri>:

  • while লুপের মাধ্যমে প্রথমবার, <author>-এর পরে পার্সার যে পরবর্তী ট্যাগ খুঁজে পায় সেটি হল <name>-এর জন্য START_TAG। depth-এর ভ্যালু বেড়ে ২ হয়েছে।
  • while লুপের মধ্যে দিয়ে দ্বিতীয়বার যাওয়ার সময়, পার্সার পরবর্তী যে ট্যাগটি পায় সেটি হল END_TAG </name>। depth-এর মান কমে ১ হয়েছে।
  • তৃতীয়বার while লুপের মাধ্যমে, পার্সার পরবর্তী যে ট্যাগটি পায় সেটি হল START_TAG <uri>। depth-এর ভ্যালু ২ পর্যন্ত বাড়ানো হয়েছে।
  • while লুপের মাধ্যমে চতুর্থবার, পার্সার যে পরবর্তী ট্যাগটি খুঁজে পায় সেটি হল END_TAG </uri>। depth-এর ভ্যালু কমে ১ হয়েছে।
  • while লুপের মাধ্যমে পঞ্চম ও শেষবার, পার্সার যে পরবর্তী ট্যাগটি দেখতে পায় সেটি হল END_TAG </author>। depth-এর মান কমে ০ হয়ে যায়, যা থেকে বোঝা যায় যে <author> এলিমেন্টটি সফলভাবে এড়িয়ে যাওয়া হয়েছে।

XML ডেটা ব্যবহার করা

উদাহরণ অ্যাপ্লিকেশনটি অ্যাসিঙ্ক্রোনাসভাবে XML ফিড ফেচ এবং পার্স করে। এটি মূল UI থ্রেড থেকে প্রসেসিং সরিয়ে দেয়। প্রসেসিং সম্পূর্ণ হলে, অ্যাপটি তার প্রধান অ্যাক্টিভিটি, NetworkActivity-এ UI আপডেট করে।

নিম্নলিখিত উদ্ধৃতিতে, loadPage() পদ্ধতি নিম্নলিখিত কাজগুলি করে:

  • XML ফিডের URL সহ স্ট্রিং ভেরিয়েবল শুরু করে।
  • ব্যবহারকারীর সেটিংস এবং নেটওয়ার্ক কানেকশন অনুমতি দিলে, downloadXml(url) পদ্ধতিকে কল করে। এই পদ্ধতি ফিড ডাউনলোড ও পার্স করে এবং UI-তে দেখানোর জন্য স্ট্রিং ফলাফল ফেরত পাঠায়।

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.
        }
    }
    ...
}

জাভা

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), যা IO থ্রেডে loadXmlFromNetwork() পদ্ধতি লঞ্চ করতে Kotlin coroutines ব্যবহার করে। এটি ফিড URL-কে প্যারামিটার হিসেবে পাস করে। loadXmlFromNetwork() পদ্ধতি ফিড ফেচ ও প্রসেস করে। এটি শেষ হলে, এটি একটি ফলাফল স্ট্রিং পাস করে।
  • withContext(Dispatchers.Main), যা মূল থ্রেডে ফিরে আসার জন্য Kotlin coroutines ব্যবহার করে, ফেরত আসা স্ট্রিং নেয় এবং UI-তে দেখায়।

Java প্রোগ্রামিং ল্যাঙ্গুয়েজে, প্রসেসটি এইভাবে কাজ করে:

  • Executor ব্যাকগ্রাউন্ড থ্রেডে loadXmlFromNetwork() পদ্ধতিটি এক্সিকিউট করে। এটি ফিড URL-কে প্যারামিটার হিসেবে পাস করে। loadXmlFromNetwork() পদ্ধতি ফিড ফেচ ও প্রসেস করে। এটি শেষ হলে, এটি একটি ফলাফল স্ট্রিং পাস করে।
  • Handler প্রধান থ্রেডে ফিরে আসার জন্য post কল করে, ফিরে আসা স্ট্রিং নেয় এবং UI-তে এটি দেখায়।

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)
            }
        }
    }
}

জাভা

// 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 থেকে কল করা হয় তা পরবর্তী স্নিপেটে দেখানো হয়েছে। এটি নিম্নলিখিত কাজগুলি করে:

  1. StackOverflowXmlParser ইনস্ট্যান্টিয়েট করে। এছাড়াও, এটি Entry অবজেক্টের List (entries) এবং title, url ও summary-এর জন্য ভেরিয়েবল তৈরি করে, যাতে XML ফিড থেকে এক্সট্র্যাক্ট করা ভ্যালু এইসব ফিল্ডের জন্য ধরে রাখা যায়।
  2. downloadUrl()-কে কল করে, যা ফিড নিয়ে আসে এবং এটিকে InputStream হিসেবে ফেরত দেয়।
  3. InputStream পার্স করতে StackOverflowXmlParser ব্যবহার করে। StackOverflowXmlParser ফিড থেকে ডেটা নিয়ে entries-এর List পূরণ করে।
  4. entries List প্রসেস করে এবং HTML মার্কআপের সাথে ফিড ডেটা একত্রিত করে।
  5. মূল অ্যাক্টিভিটি UI-তে দেখানো 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
    }
}

জাভা

// 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();
}