Recursive Traversal of Tables

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Recursive Traversal of Tables

psue
Hi,

I'm a new to Lua and finding its data description features very fascinating.

I decided to use it to document some of our WebLogic configurations.

My data file (wls.data) looks like this (only part of it shown):

Project{
        name = "CCA";
        {
                server = "maxap01",
                IP = "142.27.9.31",
                {
                        domain = "/wlsapp/prod/ivrmax",
                        class = "Production",
                        license = "21345664",
                        JDK = "1.4.2_05",
                        WebLogicVersion = "8.1SP4",
                        Console = "http://142.27.9.31:28041/console/",
                        {
                                instance = "maximus",
                                port = "28043"
                        }
                }
        },
        {
                server = "maxapp02",
                IP = "142.27.9.34",
                {
                        domain = "/wlsapp/prod/ivrmax",
                        class = "Production",
                        license = "21675756",
                        JDK = "1.4.2_05",
                        WebLogicVersion = "8.1SP4",
                        Console = "http://142.27.9.34:28041/console/",
                        {
                                instance = "test",
                                port = "28045"
                        },
                        {
                                instance = "maximus",
                                port = "28043"
                        }
                }
        }
}

Project{
        name = "TQ";
        {
                server = "snoopy",
                IP = "142.27.9.31",
                {
                        domain = "/wlsapp/prod/ivrprod",
                        class = "Production",
                        license = "1243064",
                        JDK = "1.4.2_08",
                        WebLogicVersion = "8.1SP5",
                        Console = "http://142.27.9.31:28041/console/",
                        {
                                instance = "TQ",
                                port = "28043"
                        }
                }
        }
}
==========

And my Lua source file is:

----------------
function Project (table)
        for k,v in pairs(table) do
                if type(v) == "table" then
                        Project(v)
                else
                        print(k,v)
                end
        end
end

dofile("wls.data")
-------------------

I want to convert wls.data to HTML but I haven't added the code to do that yet.  (BTW, is there an
HTML library?).

But my question is: when I run the above Lua script, it correctly reads and prints out the data file, but because of the recursion, the order is not what I wanted:

instance        maximus
port    28043
WebLogicVersion 8.1SP4
Console http://142.27.9.31:28041/console/
JDK     1.4.2_05
class   Production
domain  /wlsapp/prod/ivrmax
license 21345664
IP      142.27.9.31
server  maxap01
instance        test
port    28045
instance        maximus
port    28043
WebLogicVersion 8.1SP4
Console http://142.27.9.34:28041/console/
JDK     1.4.2_05
class   Production
domain  /wlsapp/prod/ivrmax
license 21675756
IP      142.27.9.34
server  maxapp02
name    CCA
instance        TQ
port    28043
WebLogicVersion 8.1SP5
Console http://142.27.9.31:28041/console/
JDK     1.4.2_08
class   Production
domain  /wlsapp/prod/ivrprod
license 1243064
IP      142.27.9.31
server  snoopy
name    TQ

Is there another way I can traverse the table so I can preserve the order as I HTMLize it?

Thanks,

Paul
Reply | Threaded
Open this post in threaded view
|

Re: Recursive Traversal of Tables

Bret Victor
Paul Sue <Paul.Sue <at> TELUS.com> writes:

> Is there another way I can traverse the table so I can preserve
> the order as I HTMLize it?

Your output is scrambled because pairs() traverses the table in an
unspecified order (which happens to be implemented as the opposite of
what you want).  The following Project() does what you want, provided I
understand what you want.  (But see below.)

    function Project (table)
   
        -- Traverse string keys.  Values are parameters.
        for k,v in pairs(table) do
            if type(k) == "string" then print(k,v) end
        end
       
        -- Traverse number keys.  Values are subtables.
        for i,v in ipairs(table) do
            Project(v)
        end
   
    end
   
This traverses the parameters before the subtables, which I think you
want.  But the parameters will not be traversed in order, and I'm not
sure whether you're expecting that.  When you say something like:

    t = {
           server = "snoopy",
           IP = "142.27.9.31",
           {
               domain = "foo"
           },
           {
               domain = "bar"
           }
    }

it is equivalent to:

    t = {}
    t["server"] = "snoopy"
    t["IP"] = "142.27.9.31"
    t[1] = { domain = "foo" }
    t[2] = { domain = "bar" }

In particular, t["server"] and t["IP"] are not considered "before" or
"after" one other, and the order in which pairs() traverses them is
unspecified.  t[1] and t[2], on the other hand, have numerical indices,
so you can use ipairs() to traverse them in order.

-Bret



Reply | Threaded
Open this post in threaded view
|

RE: Recursive Traversal of Tables

Daniel Collins
In reply to this post by psue
I believe that Lua tables have no implied ordering. It is certainly not
guaranteed that iterating a table with pairs will return items in the
same order they were added.

For tables used as arrays, with 1-based integer keys, the table can be
iterated in order by using ipairs. I cant see this working with your
dataset since you have a mixture of named and unnamed fields. You might
want to check out http://www.lua.org/pil/19.3.html, which explains how
to sort a table much more clearly than I can.

One way to retrieve data in a guaranteed order would be to write
functions tailored to your data rather than generic iteration code.
Something like:

function printServer(s)
        print (s.server)
        print (s.IP)
        print (s[1].domain) -- the anonymous table will end up with
key 1
        print (s[1].class)
        -- and so on
end

function Project(t)
{
        print (t.name)

        -- all the anonymous tables in the data will be entered under
consecutive integer keys
        -- ipairs will preserve their ordering.
        for i, v in ipairs(table) do
                printServer(v)
        end
}

I recognise that this means the output functions need to be tailored to
the data format, but it does give precise control over the order of
output. I see no easy way to write generic code to do this. Generic code
to output the string keys and data in alphabetic order is easy, but I
don't think this is what you want either.

- DC


Reply | Threaded
Open this post in threaded view
|

Re: Recursive Traversal of Tables

Bret Victor
In reply to this post by Bret Victor
But if you do, in fact, need your parameters to be traversed in
order, and that order is consistent throughout, this will work:

    -- Specify order for parameters.
    local paramNames = "name server IP domain class license JDK " ..
                       "WebLogicVersion Console instance port"

    function Project (table)

        -- Traverse string keys in order.  Values are parameters.
        for k in string.gmatch(paramNames, "%S+") do
            if table[k] then print(k,table[k]) end
        end

        -- Traverse number keys.  Values are subtables.
        for i,v in ipairs(table) do
            Project(v)
        end

    end


-Bret


Reply | Threaded
Open this post in threaded view
|

Re: Recursive Traversal of Tables

Daniel Collins
In reply to this post by psue
> But if you do, in fact, need your parameters to be traversed
> in order, and that order is consistent throughout, this will work:
>
>     -- Specify order for parameters.
>     local paramNames = "name server IP domain class license JDK " ..
>                        "WebLogicVersion Console instance port"
>

That's much neater than my suggestion. Another variation would be to
store the keys to the named fields in a table:

local paramNames = { "name", "server", "IP", etc...}

Then iterate paramNames using ipairs, and using that to index into the
table in Project. This avoids having to parse the string each time, and
might be faster for really large datasets. I don't know this for sure
though, and the difference might be trivial. In fact I am really just
guessing :-)

function Project(table)
        for i,v in ipairs(paramNames) do
                if table[v] then
                        print(table[v])
                end
        end

        -- iteration of subtables is as before.
end

- DC

Reply | Threaded
Open this post in threaded view
|

RE: Recursive Traversal of Tables

psue
In reply to this post by psue
RE: Recursive Traversal of Tables

Hi,

Wow!  What a helpful list!  Thanks Bret and Daniel for your suggestions.  I think that should work nicely.  Now, is there an HTML library that can help with converting to HTML?  Something like CGI.pm in perl?

Thanks,

Paul

Reply | Threaded
Open this post in threaded view
|

RE: Recursive Traversal of Tables

Tomas-14
  Hi Paul

> Wow!  What a helpful list!  Thanks Bret and Daniel for your suggestions.  I think that should work nicely.  Now, is there an HTML library that can help with converting to HTML?  Something like CGI.pm in perl?
  In CGILua, you will follow two files that could be useful: lp.lua is
an HTML preprocessor which provides the hability to include lua code inside an
HTML page; also you should take a look at serialize.lua which implements a
serialization function that takes care of the "order" of fields besides other
things.  CGILua can be found at:

http://www.keplerproject.org/cgilua

  For generating HTML, if you want something more structured, take a look
at HTK:

http://www.tecgraf.puc-rio.br/~tomas/htk

  Feel free to ask me anything about that packages.
  Tomas
Reply | Threaded
Open this post in threaded view
|

Re: Recursive Traversal of Tables

Daniel Collins
In reply to this post by psue
> Wow!  What a helpful list!  Thanks Bret and Daniel for your
suggestions.  
> I think that should work nicely.  Now, is there an HTML library that
can
> help with converting to HTML?  Something like CGI.pm in perl?

I havent used any of these, but there are some web and html related
patches listed on the lua-users wiki:
http://lua-users.org/wiki/LibrariesAndBindings