XML parsing with XMLTextDecodeAsDictionary

when i use your extension it give this error

I will test it again when i have my mobile.it should work :thinking:Strange
Can you test it as apk, and tell me what happens?

it also give the same error

i try it in app inventor and it is work fine
i do not know why it does not work in kodular

1 Like

It looks like the xmlParser class is not supported in kodular :cold_sweat:I will try to update it now :wink:

@Mohamed_Tamer the method should be something like this

import com.google.appinventor.components.runtime.Web.*;
@SimpleFunction(description = "Parse XML")
public Object XMLTextDecodeAsDictionary(String XmlText){
  return XMLTextDecodeAsDictionary(XmlText);

AI2 Component: com.google.appinventor.components.runtime.Web Class Reference

That won’t work because it only call the xmlTextDecodeasdictionary block, which is not available in kodular as well.What i’m trying to do now, is to add the xmlparser class with the extension so the extension can take the source from .

Hmmm… But this is App Inventor Library, not Kodular’s.

Then what about your JsonDecodeAsDictionary extension?

Kodular compiles the app inventor sources,that what makes the imports we add working with kodualr as well.But as kodular now compiling an old version of the sources from the app inventor, there isn’t a class called XmlParse in kodular yet.So the resolution fails.because there isn’t such file.But as app inventor using a new version from the app inventor sources the extension works there.

But the suggestion I give is not XmlParser method. It is in the com.google.appinventor.components.runtime.Web class, which might be possible because one of the staff here said they just forget to add that back in one of the topics.

Actually, this class

Will compile the latest version from the web component kodular have.Which doesn’t contain the xmlparseasdictionary block/method yet.So when you call this method in kodular it won’t be found.But, when kodular update the web source to the latest version, the method will be found, as in app inventor now.

Thank you @Mohamed_Tamer for clarification
Do kodular announce a specific date for this update?

I still can make it but it will be harder.I’m experimenting with it now :wink:

1 Like

thank you for your effort

1 Like

Hello, I finally find a way to achieve your query.


com.watermelonice.XmlTextAsDictionary.aix (11.3 KB)

I tested, and the result seems to be same as the MIT AI2 Web component.
XMLParser code is from app inventor source.


All code are here

package com.watermelonice.XmlTextAsDictionary;

import com.google.appinventor.components.annotations.*;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.*;

import com.google.appinventor.components.runtime.util.YailDictionary;
import com.google.appinventor.components.runtime.util.YailList;

import java.io.StringReader;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

@DesignerComponent(version = 1,
                    category = ComponentCategory.EXTENSION,
                    description = "To decode XML text to dictionary.<br><br> By <a href=\"https://community.kodular.io/u/WatermelonIce\">WatermelonIce</a>",
                    nonVisible = true,
                    iconName = "aiwebres/extension.png")

@SimpleObject(external = true)

public class XmlTextAsDictionary extends AndroidNonvisibleComponent {
    public XmlTextAsDictionary(final ComponentContainer container) {

    @SimpleEvent(description = "Raises when error occurred.")
    public void ErrorOccurred(String error) {
        EventDispatcher.dispatchEvent(this, "ErrorOccurred", error);
// Code from here is from app inventor source: Web.java
    @SimpleFunction(description = "XmlTextDecodeAsDictionary")
    public Object XMLTextDecodeAsDictionary(String xmlText) {
        try {
            XmlParser p = new XmlParser();
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            InputSource is = new InputSource(new StringReader(xmlText));
            parser.parse(is, p);
            return p.getRoot();
        } catch (final Exception e) {
            return new YailDictionary();


// Code down here is from app inventor sources: XmlParser.java
class XmlParser extends DefaultHandler {
  private static final String CONTENT_TAG = "$content";
  private YailDictionary root = null;
  private YailDictionary currentElement = null;
  private Deque<YailDictionary> stack = new LinkedList<>();

  public void startElement(String uri, String localName, String qname, Attributes attributes) {
    YailDictionary el = new YailDictionary();
    el.put("$tag", qname);
    el.put("$namespaceUri", uri);
    el.put("$localName", localName.isEmpty() ? qname : localName);
    if (qname.contains(":")) {
      String[] parts = qname.split(":");
      el.put("$namespace", parts[0]);
    } else {
      el.put("$namespace", "");
    YailDictionary attrs = new YailDictionary();
    for (int i = 0; i < attributes.getLength(); i++) {
      attrs.put(attributes.getQName(i), attributes.getValue(i));
    el.put("$attributes", attrs);
    el.put(CONTENT_TAG, new ArrayList<>());
    if (currentElement != null) {
      ((List<Object>) currentElement.get(CONTENT_TAG)).add(el);
      if (!currentElement.containsKey(qname)) {
        currentElement.put(qname, new ArrayList<>());
      ((List<Object>) currentElement.get(qname)).add(el);
    } else {
      root = el;
    currentElement = el;

  public void characters(char[] ch, int start, int length) {
    List<Object> items = (List<Object>) currentElement.get(CONTENT_TAG);
    if (items instanceof ArrayList) {
      String content = new String(ch, start, length);
      content = content.trim();
      if (!content.isEmpty()) {

  public void endElement(String uri, String localName, String qname) {
    for (Entry<Object, Object> e : currentElement.entrySet()) {
      if (e.getValue() instanceof ArrayList) {
        e.setValue(YailList.makeList((List<?>) e.getValue()));
    if (!stack.isEmpty()) {
      currentElement = stack.pop();

  public YailDictionary getRoot() {
    return root;

Great @WatermelonIce :+1:actually that whati’ve made exactly .Only I’ve added the XML parser in another file . But i had a small problem.So I
'v not completed it.
.S : I’ve rked it as solution as my extension wasn’t working properly

1 Like

I think that should work too.
But for convenient I just copy the whole class to my .java file (for the parser default handler), and import relevant classes. Important you mustn’t use import com.google.appinventor.components.runtime.util.*;, cuz the non-exist XmlParser.java is in that class.

Correct me if I’m wrong :sweat_smile:

1 Like

I’ve forget what error is that :sweat_smile:it was only one error in the main file and not in the XML parser file.i think my problem is that I didn’t extend the xml parser file from my main file.

1 Like

Ah, I see. :upside_down_face:

1 Like

Thank you @WatermelonIce and @Mohamed_Tamer
The extension work perfectly
:clap:t2: :clap:t2: :clap:t2: :heart_eyes: :heart_eyes:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.