On Sep 11, 2008, at 3:10 PM, David Bovill wrote:

1) Ability to reference an multi-dimensional keys dynamically. Right now we
have to build the array key reference and then use 'do'.

Yes - that was the first problem I came across. I wanted to write a
recursive function, and since you don't know how deep you will need to go you have to use "do" which destroys the reason to use arrays 9ie speed) in the first place. This makes it useless to use as a native data structure for things like arrays - or at least impossible to create generic libraries for
tree / xml data structures.

Generic conversion of XML to Array and Array to XML is possible without dynamic keys once you have decided on a way to represent the XML as an array. The XML conversion routines in the stack I provide with the article can convert between XML and arrays and don't need dynamically generated keys. I'm using the XML to Array conversion routines extensively right now with web services and have been quite happy with them.

I've attached latest version of these handlers at the bottom of this email for reference. The entry points are ConvertArrayToXML() and ConvertXMLToArray(). Look at ConvertXMLNodeToArray() for an example of the recursive call.

I have another scenario where I had to resort to 'do' though. I'm converting SQL queries to a hierarchal array but unlike XML SQL results have no sense of hierarchy. So I have a couple of 'do' statements in the code which I will promptly replace when/if the engine is updated to support dynamic keys.

2) Ability to pass a key of an array by reference. Currently you can't do
this:

OK. But "theArray[1]" is just another array - so surely you can do this:

on mouseUp
  put "Hi There" into theArray[1]["name"]
  put theArray[1] into firstArray
  DoSomething firstArray
end mouseUp

command DoSomething @pArrayA
  ....
end DoSomething

 Which I almost prefer for legibility - so that's no biggy for me?

Right, not a huge deal. But you hate to have to make an extra copy when dealing with large data sets and it is extra lines of code. You left off one line of the code though. You need to put firstArray back into theArray[1] after calling DoSomething in order to get a pass by ref equivalent:

put theArray[1] into firstArray
DoSomething firstArray
put firstArray into theArray[1]

3) Ability to reference elements of an array in the order they were added to the array:

Totally. I posted about this earlier. I have to do a lot of scripting to get
around this


Yes, it is unfortunate that we have to resort to custom sorts (see SortArrayKeysWithXMLOrdering in XML code) or numeric sorts in order to iterate through keys sequentially. Hopefully that will be addressed in the near future.

Example of iterating sequentially through a numerically keyed array:

put the keys of theArrayA into theKeys
sort lines of theKeys numeric
repeat for each line theIndex in theKeys
   ....
end repeat

All that being said the new arrays have been a huge productivity boost on my end. Code is running faster, is easier to read and easier to write.


Regards,

--
Trevor DeVore
Blue Mango Learning Systems
ScreenSteps: http://www.screensteps.com
Developer Resources: http://revolution.bluemangolearning.com



--
-- Converts an XML tree into a Revolution multi-dimensional array.
-- A nodes attributes will be stored as an array of it's "@attributes" key. -- Node names will retain the sequence information (i.e. node[1], node[2], etc.). -- This information is necessary to determine order that keys should be processed in. Example:
-- set the itemDelimiter to "["
-- put the keys of theArray into theKeys
-- sort theKeys numeric by the last item of each
--
-- pUseValueKey: The default value is false. In this case you get an array that has an @attributes -- key for nodes that have attributes and either a) no value or b) only child nodes. Otherwise it contains the node contents. -- Set to true if you want to store a nodes value in the '@value' key. This will allow a key to have
-- both attributes (in @attributes key) and a value (in @value key).
--
function ConvertXMLToArray pXML, pStoreEncodedAs, pUseValueKey
    local theArray,theResult,theRootNode,theTreeID
    local theXMLEncoding

    ## Create an XML tree from XML text
    put revCreateXMLTree(pXML, true, true, false) into theTreeID

    if theTreeID is an integer then
        ## Determine the encoding of the XML, default to UTF-8
put matchtext(pXML, "<\?xml (.*)encoding=" & quote & "(.*)" & quote & "\?>", versionMatch, theXMLEncoding) into theResult
        if theXMLEncoding is empty then put "utf-8" into theXMLEncoding

        ## Now convert to array.
## The 1st dimension has one key which is the name of the root node.
        put revXMLRootNode(theTreeID) into theRootNode
if theRootNode is not empty and not(theRootNode begins with "xmlerr,") then put ConvertXMLNodeToArray(theTreeID, theRootNode, theXMLEncoding, pStoreEncodedAs, pUseValueKey) into theArray[theRootNode]
        end if
    end if

    return theArray
end ConvertXMLToArray


function ConvertXMLTreeToArray pXMLTree, pStoreEncodedAs, pUseValueKey
return ConvertXMLToArray(revXMLText(pXMLTree), pStoreEncodedAs, pUseValueKey)
end ConvertXMLTreeToArray


--
-- Converts a multi-dimensional array to an XML tree.
-- The array should contain one key in the 1st dimension which
-- will become the root node. Attributes of a node should be stored
-- as an array in the @attributes key. Sequence information for multiple
-- nodes with the same name should be included in the node name using
-- brackets (i.e. node[1], node[2], node[3]).
-- Returns an xml tree id (integer) or an error message.
--
function ConvertArrayToXML pArray, pArrayEncoding, pStoreEncodedAs
    local theError,theRootNode,theXML,theXMLTree

## if pArrayEncoding is empty then current platform encoding is assumed
    if pStoreEncodedAs is empty then put "UTF-8" into pStoreEncodedAs

## Create XML for root node. Note that we take extra steps in order to support ## converting an array that only represents part of a tree rather than the entire tree.
    ## In this case there may be multiple nodes at the root level.
    put line 1 of the keys of pArray into theRootNode
    set the itemdelimiter to "["
    put "<" & item 1 of theRootNode & "/>" into theXML

    ## Create XML needed to create tree
    put format("<?xml version=\"1.0\" encoding=\"%s\"?>%s", \
            pStoreEncodedAs, theXML) into theXML
    put revCreateXMLTree(theXML, true, true, false) into theXMLTree

    if theXMLTree is an integer then
        ## Loop over all nodes at root level
        put SortArrayKeysWithXMLOrdering(pArray) into theNodes

        ## Create tree using helper function
        repeat for each line theNode in theNodes
ConvertArrayDimensionToXML pArray[theNode], theXMLTree, slash & theNode, \
                    pArrayEncoding, pStoreEncodedAs
            put the result into theError

            if theError is not empty then exit repeat
        end repeat

        if theError is not empty then
            ## something went wrong, clean bad tree
            revDeleteXMLTree theXMLTree
        end if
    else
        put theXMLTree into theError
    end if

    if theError is not empty then
        return theError
    else
        return theXMLTree
    end if
end ConvertArrayToXML

--
-- Helper function for ConvertArrayToXML
-- Converts the multi-dimensional array pArray to nodes in pTreeID. -- Calls itself recursively.
-- Returns error message.
--
private command ConvertArrayDimensionToXML pArray, pTreeID, pNode, pArrayEncoding, pStoreEncodedAs
    local theError,theKey,theKeys,theNode

    ## A workaround for fact that Revolution does not return
    ## keys in the order we created them
    put SortArrayKeysWithXMLOrdering(pArray) into theNodes

    ## Arrays might have sequencing info in name
    ## (i.e. step[1], step[2], ... )
    set the itemdelimiter to "["

    repeat for each line theFullNode in theNodes
        put item 1 of theFullNode into theNode

## Look for attributes. These will be added as attributes to pNode.
        if theNode is "@attributes" then
repeat for each line theKey in the keys of pArray[theFullNode]
                revSetXMLAttribute pTreeID, pNode, theKey, \
                        EncodeString(pArray[theFullNode][theKey], \
                        pArrayEncoding, pStoreEncodedAs)
                if the result begins with "xmlerr," then
put the result && "(setting attribute" && theKey && "for node" && pNode & ")" into theError
                end if

                if theError is not empty then exit repeat
            end repeat

        else if theNode is "@value" then
## This XML tree is using complex structure. Node is the value of the parent node revPutIntoXMLNode pTreeID, pNode, EncodeString(pArray[theFullNode], pArrayEncoding, pStoreEncodedAs)
            if the result begins with "xmlerr," then
put the result && "(adding child node" && theNode && "to node" && pNode & ")" into theError
            end if

        else
            if the keys of pArray[theFullNode] is not empty then
## Node has children. Add node to XML tree then call self recursivly to create children nodes.
                revAddXMLNode pTreeID, pNode, theNode, empty
                if the result begins with "xmlerr," then
put the result && "(adding node" && theNode & ")" into theError
                end if

                if theError is empty then
ConvertArrayDimensionToXML pArray[theFullNode], pTreeID, pNode & slash & theFullNode, \
                            pArrayEncoding, pStoreEncodedAs
                    put the result into theError
                end if
            else
## Node has no children but possibly a value. Create node and add value (which may be empty).
                revAddXMLNode pTreeID, pNode, theNode, \
EncodeString(pArray[theFullNode], pArrayEncoding, pStoreEncodedAs)
                if the result begins with "xmlerr," then
put the result && "(adding child node" && theNode && "to node" && pNode & ")" into theError
                end if
            end if
        end if

        if theError is not empty then exit repeat
    end repeat

    return theError
end ConvertArrayDimensionToXML


--
-- Revolution array keys are never guaranteed to be in order you created -- them in so we must come up with some other way of maintaining -- proper sequence. For arrays representing XML, the XML syntax is -- used (i.e. node[1], node[2], etc.). This handler will sort keys that use -- this syntax for representing sequence.
--
function SortArrayKeysWithXMLOrdering pArray
    put the keys of pArray into theKeys
    set the itemdelimiter to "["
    sort theKeys numeric by the last item of each -- 1], 2], 3], etc.

    set the wholematches to true
    put lineoffset("@attributes", theKeys) into theLineNo
    if theLineNo > 0 then
        delete line theLineNo of theKeys
    end if

    return theKeys
end SortArrayKeysWithXMLOrdering


--
-- Helper function for ConvertXMLToArray.
-- Converts an XML node to a multi-dimensional array. -- Calls itself recursively.
--
private function ConvertXMLNodeToArray pTreeID, pNode, pXMLTreeEncoding, pStoreEncodedAs, pUseValueKey
    local theArrayA,theAttributes,theChildNode,theKey

## Look for attributes of the node. Store as array in "@attributes" key
    put revXMLAttributes(pTreeID, pNode, tab, cr) into theAttributes
    if theAttributes is not empty then
put EncodeString(theAttributes, pXMLTreeEncoding, pStoreEncodedAs) into theAttributes
        split theAttributes by cr and tab -- create array
        put theAttributes into theArrayA["@attributes"]
    end if

    ## Look for children nodes.
    set the itemdelimiter to slash
    put revXMLFirstChild(pTreeID, pNode) into theChildNode
    if theChildNode is empty or theChildNode begins with "xmlerr," then
put EncodeString(revXMLNodeContents(pTreeID, pNode), pXMLTreeEncoding, pStoreEncodedAs) into theValue if word 1 to -1 of theValue is empty and the keys of theArrayA is not empty then
            ## Empty node that has attributes
            return theArrayA
        else if pUseValueKey then
            ## Force value into @value
            put theValue into theArrayA["@value"]
            return theArrayA
        else
## Single Node with value: Return value. Attributes are ignored.
            return theValue
        end if
    else
## Child nodes were found. Recursively call self and store result in array. repeat while theChildNode is not empty and not (theChildNode begins with "xmlerr,")
            put the last item of theChildNode into theKey
put ConvertXMLNodeToArray(pTreeID, theChildNode, pXMLTreeEncoding, pStoreEncodedAs, pUseValueKey) into theArrayA[theKey] put revXMLNextSibling(pTreeID, theChildNode) into theChildNode
        end repeat

        return theArrayA
    end if
end ConvertXMLNodeToArray

--
-- Helper function for converting the encoding of strings when converting to and from XML.
--
private function EncodeString pString, pInEncoding, pOutEncoding
    ## convert utf-8 to utf8 for uniencode/decode
    replace "-" with empty in pInEncoding
    replace "-" with empty in pOutEncoding

    if pInEncoding is not empty then
-- if pOutEncoding is empty then pString will be converted to the current platform encoding
        return unidecode(uniencode(pString, pInEncoding), pOutEncoding)
    else
        if pOutEncoding is not empty then
-- if pInEncoding is empty then pString is assumed to be in the current platform encoding return unidecode(uniencode(pString, pInEncoding), pOutEncoding)
        else
            return pString
        end if
    end if
end EncodeString
_______________________________________________
use-revolution mailing list
[email protected]
Please visit this url to subscribe, unsubscribe and manage your subscription 
preferences:
http://lists.runrev.com/mailman/listinfo/use-revolution

Reply via email to