Newbie XML Question

Mark Brownell gizmotron at
Tue Dec 14 12:18:05 EST 2004

On Monday, December 13, 2004, at 12:29 PM, Bill Marriott wrote:
> <Register Station="A">
>    <Purchase Date="12/13/2004" Time="14:26:03" 
> DateTime="20041213142603" Order="1">
>        <Buyer CustomerID="1234" />
>        <Item UPC="04905004" Price="0.40"/>
>        <Description>Cherry Coca-Cola</Description>
>    </Purchase>
>    <Purchase Date="12/13/2004" Time="14:26:14" 
> DateTime="20041213142614" Order="1">
>        <Buyer CustomerID="1234" />
>        <Item UPC="03424005" Price="0.65"/>
>        <Description>Hershey's Chocolate Bar</Description>
>    </Purchase>
>    <Purchase Date="12/13/2004" Time="15:09:25" 
> DateTime="20041213150925" Order="2">
>        <Buyer CustomerID="4567" />
>        <Item UPC="02880125" Price="6.95"/>
>        <Description>Marlboro Cigarettes</Description>
>    </Purchase>
> </Register>
> In other words, Bob had two customers. The first customer bought two 
> items (Order 1), and the second customer bought one item (Order 2).
> Each register spits out a tape like this, starting with Order=1 and 
> continuing until the store closes. At the end of the day, Bob would 
> like to feed these tapes into his computer running Revolution and get 
> one "tape" of all his items, re-numbered sequentially.
> * Bob can't just tape them together (append them) because the Order 
> numbers would conflict. Each register starts numbering at "1" when the 
> store opens.
> * There will never be overlapping orders; only one cash register is 
> active at any given time. (Bob is a sole proprietor who runs from one 
> to the other.)
> The problem is, I don't know how to manipulate blocks of XML like 
> this. Do I have to convert the whole XML file into some kind of table 
> first? Do I have to walk through each and every node and every 
> attribute? Is there nothing like "sort lines of foobar ascending by 
> item 5 of each?" Actually, I don't even know how to walk through the 
> nodes since the functions only seem to return the first instance...
> I really would like to do something like select/extract all the 
> Purchases where the Order ID = n and bring along all the related 
> attributed and child elements. But I haven't a clue how to do that.
> I've gotten as far as I have through reading the "XML Demo 1" stack 
> and "XML construction kit" but I've hit a wall now. Some helpful 
> advice would be very welcome... and posisbly helpful for other XML 
> newbies on the list.
> Bill


I'm having trouble posting to the list?

Being new here you would not know about my pull-parsers. This task of 
yours could be handled so easy with a pull parser. First of all you 
could create an array of purchase objects using my pull-parser function 
for creating an array out of multiple XML elements, in your case , 
purchases. So here it is done for you:

Step 1. put XML data of cash register a & cash register b into 
gBothXMLtapes ( field "stashHere" )

Step 2. Use my pull-parser functions to create one array of all 
purchase data (see functions below)
...paste the functions below into your application at some button 
before using them.

======== Use this in a button click:

-- Paste all this below into a button & use field "stashHere"  --  to 
enter your XML & field "show" to see the results.

on mouseUp
   put the text of field "stashHere" into gBothXMLtapes
   put 1 into spot
   put "" into stashAttributesDT
   put "" into gTransXML
   put "<Purchase " into t1
   put "</Purchase>" into t2
   put "" into tempXML
   put getElementsArray(t1, t2, gBothXMLtapes) into bothTapesArray
     put bothTapesArray[spot] into stashThis
     if stashThis = empty then exit repeat
     put getAttribute("DateTime", stashThis) into tAttributeDT
     delete char 1 to 8 of tAttributeDT
     put tAttributeDT & return after stashAttributesDT
     put "<" &  tAttributeDT & ">" into a1
     put "</" &  tAttributeDT & ">" into a2
     put a1 & t1 & stashThis & t2 & a2 into zapped
     put zapped & return after tempXML
     add 1 to spot
   end repeat
   sort lines of stashAttributesDT
   -- this sorting is the solution based on your XML and the use by two 
cash registers.
   put 1 into spot2
   put "<xml>"  & return into newXMLDoc
   repeat for each line X in stashAttributesDT
     put "<" & X & ">" into z1
     put "</" & X & ">" into z2
     put getElement(z1, z2, tempXML) into tXmlElement
     put return & tXmlElement & return after newXMLDoc
   end repeat
   put "</xml>"  & return after newXMLDoc
   put newXMLDoc into field "show"
end mouseUp

-- That's it. You now have a newly transformed single XML document 
based on the Date-Time attribute that -- will appear in the "show" text 

-- I hope that helps, -- Mark


--Paste these functions:
-- put getElement("<record>", "</record>", tVar) into theElement
function getElement tStTag, tEdTag, stngToSch
   put empty into zapped
   put the number of chars in tStTag into dChars
   put offset(tStTag,stngToSch) into tNum1
   put offset(tEdTag,stngToSch) into tNum2
   if tNum1 < 1 then
     return "error"
     exit getElement
   end if
   if tNum2 < 1 then
     return "error"
     exit getElement
   end if
   put char (tNum1 + dChars) to (tNum2 - 1) of stngToSch into zapped
   return zapped
end getElement

-- put getAttribute("name", tVar) into theAttribute
function getAttribute tAttribute, strngToSearch
   put empty into zapA
   put quote into Qx
   if char 1 of tAttribute = space then
     put tAttribute & "=" & Qx into tAttributeX
     put space & tAttribute & "=" & Qx into tAttributeX
   end if
   put the number of chars in tAttributeX into dChars
   put offset(tAttributeX,strngToSearch) into tNum1
   if tNum1 < 1 then
     return "error"
     exit getAttribute
   end if
   put tNum1 + dChars into tNumX
   put offset(Qx,strngToSearch,tNumX) into tNumZ
   if tNumX < 1 then
     return "error"
     exit getAttribute
   end if
   if tNumZ < 1 then
     return "error"
     exit getAttribute
   end if
   put char tNumX to (tNumX + (tNumZ - 1)) of strngToSearch into zapA
   return zapA
end getAttribute

-- put getElementsArray("<record>", "</record>", tVar) into theArray
function getElementsArray tStartTag, tEndTag, StringToSearch
   put empty into tArray
   put 0 into tStart1
   put 0 into tStart2
   put 1 into tElementNum
   put the number of chars in tStartTag into dChars
     put offset(tStartTag,StringToSearch,tStart1) into tNum1
     put (tNum1 + tStart1) into tStart1
     if tNum1 < 1 then exit repeat
     put offset(tEndTag,StringToSearch,tStart2) into tNum2
     put (tNum2 + tStart2) into tStart2
     if tNum2 < 1 then exit repeat
     --if tNum2 < tNum1 then exit repeat
     put char (tStart1 + dChars) to (tStart2 - 1) of StringToSearch into 
     put zapped into tArray[tElementNum]
     add 1 to tElementNum
   end repeat
   return tArray
end getElementsArray

More information about the use-livecode mailing list