B4J Question Trouble parsing an XML string!

vfafou

Well-Known Member
Licensed User
Longtime User
Hello!

I'm using XML2Map for XML parsing needs. There is an XML I need to parse, but it is a bit complex.
I need some help to parse it properly.
Here is a sample of it:
B4X:
<NewResponse>
    <ExtResult rank="1" finalRank="0" type="0">
        <NewItems>
            <NewItem Id1="1" Id2="4259" flag="0" q1="0" q2="1" name="Typed string" lang="0"/>
        </NewItems>
        <Results>
            <Result Id="0" number1="176.45" number2="250.84" number3="152" dist="0" resultType="1">
                <NewString string="Area 1" stringType="1"/>
                <NewString string="Area 2" stringType="5"/>
                <NewString string="Area 3" stringType="4"/>
                <NewString string="Area 4" stringType="3"/>
                <NewString string="Area 5" stringType="2"/>
                <NewString string="99990" stringType="7"/>
            </Result>
            <Result Id="0" number1="90.28" number2="453.23" number3="198" dist="0" resultType="1">
                <NewString string="Area 6" stringType="1"/>
                <NewString string="Area 7" stringType="5"/>
                <NewString string="Area 8" stringType="4"/>
                <NewString string="Area 9" stringType="3"/>
                <NewString string="Area 0" stringType="2"/>
                <NewString string="88888" stringType="7"/>
            </Result>
        </Results>
    </ExtResult>
</NewResponse>
Thank you in advance!
 
Last edited:

npsonic

Active Member
Licensed User
It's not quite clear what you are asking.

Isn't it just easy as this code example? Here's something that I quickly wrote for you.
If you decide to use method "FindValue" then remember that it might take time to find value from huge xml and it only returns first found value, so changes to method might be required.
B4X:
Sub ParseXml
    Dim xml As Xml2Map
    xml.Initialize 
    Dim m As Map = xml.Parse($"<NewResponse>
                                <ExtResult rank="1" finalRank="0" type="0">
                                    <NewItems>
                                        <NewItem Id1="1" Id2="4259" flag="0" q1="0" q2="1" name="Typed string" lang="0"/>
                                    </NewItems>
                                    <Results>
                                        <Result Id="0" number1="176.45" number2="250.84" number3="152" dist="0" resultType="1">
                                            <NewString string="Area 1" stringType="1"/>
                                            <NewString string="Area 2" stringType="5"/>
                                            <NewString string="Area 3" stringType="4"/>
                                            <NewString string="Area 4" stringType="3"/>
                                            <NewString string="Area 5" stringType="2"/>
                                            <NewString string="99990" stringType="7"/>
                                        </Result>
                                        <Result Id="0" number1="90.28" number2="453.23" number3="198" dist="0" resultType="1">
                                            <NewString string="Area 6" stringType="1"/>
                                            <NewString string="Area 7" stringType="5"/>
                                            <NewString string="Area 8" stringType="4"/>
                                            <NewString string="Area 9" stringType="3"/>
                                            <NewString string="Area 0" stringType="2"/>
                                            <NewString string="88888" stringType="7"/>
                                        </Result>
                                    </Results>
                                </ExtResult>
                            </NewResponse>"$)
    Log(m)
  
    Dim result As Object = FindValue("number1",m)
    Log(result)
    Dim result As Object = FindValue("Results",m)
    Log(result)
End Sub

Sub FindValue (Key As String, XmlMap As Map) As Object
    Dim v As Object
    For Each k As String In XmlMap.keys
        If Key.EqualsIgnoreCase(k) Then Return XmlMap.Get(k)
        If XmlMap.Get(k) Is Map Then
            v = FindValue(Key,XmlMap.Get(k))
            If v <> Null Then Return v
        End If
        If XmlMap.Get(k) Is List Then
            Dim l As List = XmlMap.Get(k)
            For Each o As Object In l
                If o Is Map Then
                    v = FindValue(Key,o)
                    If v <> Null Then Return v
                End If
            Next
            l.Clear
        End If
    Next
    Return Null
End Sub
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
Hello npsonic!
Thank you for your response!
After rereading my post, I've noticed that you are right that it was not clear what I want to do.
Well, for every <Result> I want to get "number1", "number2", "number2" and all <NewStrings>, in order to concatenate some of these values and show them as items of a listview!
I hope it's clearer now! :)
 
Upvote 0

npsonic

Active Member
Licensed User
Okay, so here's little example.
Just use maps to get values you need from points where Log is used. If you run this example you will see from the B4A log view how values you need are now easily accessible.

B4X:
Sub ParseXml
    Dim xml As Xml2Map
    xml.Initialize
    Dim m As Map = xml.Parse($"<NewResponse>
                                <ExtResult rank="1" finalRank="0" type="0">
                                    <NewItems>
                                        <NewItem Id1="1" Id2="4259" flag="0" q1="0" q2="1" name="Typed string" lang="0"/>
                                    </NewItems>
                                    <Results>
                                        <Result Id="0" number1="176.45" number2="250.84" number3="152" dist="0" resultType="1">
                                            <NewString string="Area 1" stringType="1"/>
                                            <NewString string="Area 2" stringType="5"/>
                                            <NewString string="Area 3" stringType="4"/>
                                            <NewString string="Area 4" stringType="3"/>
                                            <NewString string="Area 5" stringType="2"/>
                                            <NewString string="99990" stringType="7"/>
                                        </Result>
                                        <Result Id="0" number1="90.28" number2="453.23" number3="198" dist="0" resultType="1">
                                            <NewString string="Area 6" stringType="1"/>
                                            <NewString string="Area 7" stringType="5"/>
                                            <NewString string="Area 8" stringType="4"/>
                                            <NewString string="Area 9" stringType="3"/>
                                            <NewString string="Area 0" stringType="2"/>
                                            <NewString string="88888" stringType="7"/>
                                        </Result>
                                    </Results>
                                </ExtResult>
                            </NewResponse>"$)
 
    Dim value As Object = FindValue2("Results",m)
    If value <> Null Then
        Dim results As Map = value
        Dim result As List = results.Get("Result")
        Dim attributes As Map, newstring As List
        For Each res As Map In result
            attributes = res.Get("Attributes")
            Log(attributes)
            newstring = res.Get("NewString")
            For Each mns As Map In newstring
                attributes = mns.Get("Attributes")
                Log(attributes)
            Next
            Log("---------------------------")
        Next
    End If
End Sub

Sub FindValue2 (Key As String, XmlMap As Map) As Object
    Dim v As Object
    For Each k As String In XmlMap.keys
        If Key.EqualsIgnoreCase(k) Then Return XmlMap.Get(k)
        If XmlMap.Get(k) Is Map Then
            v = FindValue(Key,XmlMap.Get(k))
            If v <> Null Then Return v
        End If
    Next
    Return Null
End Sub
 
Last edited:
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
Hello npsonic!
Your code is working very good but it gives an error at:
B4X:
For Each res As Map In result
The error is:
B4X:
java.lang.ClassCastException: anywheresoftware.b4a.objects.collections.Map$MyMap cannot be cast to java.util.List
and I can't figure out why!!!
 
Upvote 0

npsonic

Active Member
Licensed User
Hello npsonic!
Your code is working very good but it gives an error at:
B4X:
For Each res As Map In result
The error is:
B4X:
java.lang.ClassCastException: anywheresoftware.b4a.objects.collections.Map$MyMap cannot be cast to java.util.List
and I can't figure out why!!!
I made assumption according to your previous post that key "Result" in your xml does contain only maps. If it can also contain lists, you can declare res as an object and check if it is a List or Map.

You must handle everything you get from xml properly.

B4X:
For Each res As Object In result
    If res Is Map Then
        attributes = res.Get("Attributes")
        Log(attributes)
        newstring = res.Get("NewString")
        For Each mns As Map In newstring
            attributes = mns.Get("Attributes")
            Log(attributes)
        Next
    Else
        Log(attributes)
    End If
    Log("---------------------------")
Next
 
Upvote 0
Top