# Saturday, January 14, 2006

Updated FLL with more functionality
I don't have time (it's late) to comment too much on the changes I've made to the regexp.fll. I significantly enhanced the functionality of the regexp() function when it is splitting. You can now split results into an array or a cursor. I also fixed a couple of bugs in the code having to do with the splitting feature. In any event, the documentation from my previous blog entry is still good, but now you can send in parameter nFunctionType = 4 and you will get a cursor. Also, if you are using nFunctionType = 3 or 4, you can specify a Visual FoxPro command for the regular expression engine to execute each time a match is found (think of it as a callback function of sorts).

An XML parsing example
This library is really shaping up, but I think there are lots of other possibilities that haven't been explored yet (Comment here on the blog or send me any good ideas for functionality you might have - I'd love to hear them). One thing I knew the library could do is parse XML. Using some regular expressions I found freely available on the internet, I created some sample code (see below) to show of the wonderous abilities of regular expressions as well as the new functionality in the FLL.

More to come
As cool as this may be, I'm still not really doing them (regular expressions or this FLL) justice. When I get more time, I'll be back to update the documentation and show how this FLL gives us abilities in Visual FoxPro that we didn't ever have before. Here's the download and some example code (the ParseXML function is the guts of it and you need the newest regexp.fll to run this). Enjoy.

Download the regexp.fll (63 KB approx)

*!* Example of using the ParseXML function
#DEFINE CREATEANARRAY 2
#DEFINE CREATEACURSOR 3

LOCAL lcArrayToCreate, lcCursorToCreate, lnTotal, lnCounter
*!* Here's some sample XML
*!* just to demonstrate
TEXT TO lcSampleXML NOSHOW PRETEXT 7
<?xml version="1.0"?>
<samples>
<sample>Visual FoxPro Rocks!</sample>
<sample>Does more before breakfast</sample>
<sample>than other languages do all day</sample>
</samples>
ENDTEXT

*!* Or you can try this using an XML file
*!* You can get some sample XML files at
*!* ftp://sunsite.unc.edu/pub/sun-info/standards/xml/eg/shakespeare.1.01.xml.zip
*!* Once you have extracted them then
*!* comment out the TEXT/ENDTEXT code above
*!* lastly you can something like the following
*!* to load the example XML files
*!* lcSampleXML = FILETOSTR(GETFILE())

*!* Create an array
DIMENSION aryXMLDoc(1)
lcArrayToCreate = "aryXMLDoc"
lnTotal = ParseXML(lcSampleXML, lcArrayToCreate, CREATEANARRAY)
CLEAR
FOR lnCounter = 1 TO lnTotal
    ?aryXMLDoc(lnCounter)
ENDFOR
MESSAGEBOX("Parsed XML has been output to the screen from the array." ;
        + CHR(13) + "Click OK to continue with the next example.", ;
        64, "XML Parsing Complete")

*!* Create a cursor
lcCursorToCreate = "crsXMLDoc"
lnTotal = ParseXML(lcSampleXML, lcCursorToCreate, CREATEACURSOR)
IF lnTotal > 0
    GO TOP IN (lcCursorToCreate)
    BROWSE
ENDIF

MESSAGEBOX("Click OK to run the final example.", ;
        64, "Begin Final XML Parsing Example")
        
*!* Create a cursor, but also execute some
*!* VFP code as the C++ parser runs.
*!* This can be used to manipulate the data
*!* as it is retrieved or whatever.
*!* The C++ parser in the FLL
*!* will execute whatever command you tell it to
lcCursorToCreate = "crsXMLDoc"
lcVFPCommand = "DO AppendVFPRocks"
lnTotal = ParseXML(lcSampleXML, lcCursorToCreate, CREATEACURSOR, lcVFPCommand)
IF lnTotal > 0
    CLEAR
    GO TOP IN (lcCursorToCreate)
    SCAN ALL
        ? Splits
    ENDSCAN
ENDIF

**************************
PROCEDURE AppendVFPRocks
**************************
    Replace splits WITH "VISUAL FOXPRO ROCKS!" + splits
ENDPROC


*******************************
FUNCTION ParseXML (tcXML, tcName, tnType, tcCommand)
*******************************
*!* This Function is made possible by the work
*!* of Robert Cameron...
*******************************
*!* REX/Perl 1.0
*!* Robert D. Cameron "REX: XML Shallow Parsing with Regular Expressions",
*!* Technical Report TR 1998-17, School of Computing Science, Simon Fraser
*!* University, November, 1998.
*!* Copyright (c) 1998, Robert D. Cameron.
*!* The following code may be freely used and distributed provided that
*!* this copyright and citation notice remains intact and that modifications
*!* or additions are clearly identified.
*!* http://www.cs.sfu.ca/~cameron/REX.html
*******************************
*!* 01-14-2006: Translated and modified his expressions
*!* for use in Visual FoxPro with the regexp.fll
*!* by Craig Boyd http://www.sweetpotatosoftware.com/spsblog
*******************************

    LOCAL lcTextSE, lcUntilHyphen, ;
        lcUntil2Hyphens, lcCommentCE, lcUntilRSBs, ;
        lcCDATA_CE, lcS, lcNameStrt, lcNameChar, ;
        lcName, lcQuoteSE, lcDT_IdentSE, ;
        lcMarkupDeclCE, lcS1, lcUntilQMs, ;
        lcPI_Tail, lcDT_ItemSE, lcDocTypeCE, ;
        lcDeclCE, lcPI_CE, lcEndTagCE, lcAttValSE, ;
        lcElemTagCE, lcMarkupSPE, lcXML_SPE, ;
        lcExpression, lvReturn
    IF !("\REGEXP.FLL" $ SET("Library"))
        SET LIBRARY TO LOCFILE("regexp.fll", "FLL")
    ENDIF
    lcTextSE = "([^<]+"
    lcUntilHyphen = "[^-]*-"
    lcUntil2Hyphens = lcUntilHyphen + "(?:[^-]" + lcUntilHyphen + ")*-"
    lcCommentCE = lcUntil2Hyphens + ">?"
    lcUntilRSBs = "[^\]]*](?:[^\]]+])*]+"
    lcCDATA_CE = lcUntilRSBs + "(?:[^\]>]" + lcUntilRSBs + ")*>"
    lcS = "[ \n\t\r]+"
    lcNameStrt = "[A-Za-z_:]|[^\x00-\x7F]"
    lcNameChar = "[A-Za-z0-9_:.-]|[^\x00-\x7F]"
    lcName = "(?:" + lcNameStrt + ")(?:" + lcNameChar + ")*"
    lcQuoteSE = '"[^"]*"|' + "'[^']*'"
    lcDT_IdentSE = lcS + lcName + "
(?:" + lcS + "(?:" + lcName + "|" + lcQuoteSE + "))*"
    lcMarkupDeclCE = '(?:[^\]"
' + "'><]+|" + lcQuoteSE + ")*>"
    lcS1 = "[\n\r\t ]"
    lcUntilQMs = "[^?]*\?+"
    lcPI_Tail = "\?>|" + lcS1 + lcUntilQMs + "(?:[^>?]" + lcUntilQMs + ")*>"
    lcDT_ItemSE = "<(?:!(?:--" + lcUntil2Hyphens + ">|[^-]" + lcMarkupDeclCE + ")|\?" + lcName + "(?:" + lcPI_Tail + "))|%" + lcName + ";|" + lcS
    lcDocTypeCE = lcDT_IdentSE + "(?:" + lcS + ")?(?:\[(?:" + lcDT_ItemSE + ")*](?:" + lcS + ")?)?>?"
    lcDeclCE = "--(?:" + lcCommentCE + ")?|\[CDATA\[(?:" + lcCDATA_CE + ")?|DOCTYPE(?:" + lcDocTypeCE + ")?"
    lcPI_CE = lcName + "(?:" + lcPI_Tail + ")?"
    lcEndTagCE = lcName + "(?:" + lcS + ")?>?"
    lcAttValSE = '"[^<"]*"|' + "'[^<']*'"
    lcElemTagCE = lcName + "
(?:" + lcS + lcName + "(?:" + lcS + ")?=(?:" + lcS + ")?(?:" + lcAttValSE + "))*(?:" + lcS + ")?/?>?"
    lcMarkupSPE = "
<(?:!(?:" + lcDeclCE + ")?|\?(?:" + lcPI_CE + ")?|/(?:" + lcEndTagCE + ")?|(?:" + lcElemTagCE + ")?))"
    lcXML_SPE = lcTextSE + "
|" + lcMarkupSPE

    lcExpression = lcXML_SPE
    IF VARTYPE(tcCommand) = "
C"
        lvReturn = RegExp(tcXML, lcExpression, tnType, tcName, tcCommand)
    ELSE
        lvReturn = RegExp(tcXML, lcExpression, tnType, tcName)
    ENDIF
    RETURN (lvReturn)
ENDFUNC

Saturday, January 14, 2006 11:23:09 AM (GMT Standard Time, UTC+00:00)  #    Comments [6]
Thursday, September 21, 2006 10:37:59 PM (GMT Daylight Time, UTC+01:00)
Craig, any chance of adding this to VFPX?
Friday, September 22, 2006 6:26:29 AM (GMT Daylight Time, UTC+01:00)
Hi Garrett,

Sure. When I am working on VFPX, I am helping with the GDIPlusX library. But, that should be wrapping up pretty soon given the hard work that Bo Durban and Cesar Chalom have been putting into it lately. Then I was thinking that I would start a few projects out there of my own and this could certainly be one of them. Would you be interested in working on it if it got added?
Friday, September 22, 2006 11:01:47 PM (GMT Daylight Time, UTC+01:00)
In theory, happy to. :-) In practice, we'll have to see what happens.
Wednesday, October 04, 2006 12:00:28 AM (GMT Daylight Time, UTC+01:00)
I just had to write the following line:

REPLACE city WITH REGEXP(ORGCITYST, "(.*)\s(\w+)\s*", 1, "\1"), ;
st WITH REGEXP(ORGCITYST, "(.*)\s(\w+)\s*", 1, "\2") ALL

Is it feasible to do something like:

REGEXP(ORGCITYST, "(.*)\s(\w+)\s*", 4, '', "REPLACE city with \1, st with \2")

Wednesday, October 04, 2006 10:06:47 AM (GMT Daylight Time, UTC+01:00)
Garrett,

Despite the large number of downloads, I am beginning to get the impression that you, Rick Borup, and I are the only ones using this library. :) As to your suggestion... Yes, it would be possible to implement something like that into the FLL, but I'm not sure whether I could justify the effort to value ratio. I need to think about it for a bit. The parsing would be pretty straightforward in the scenario you have presented, but I would like to take into consideration all of the other perl-like formatting strings. Perhaps it is just a matter of parsing... in that case it would be pretty cool and easy to do.
Wednesday, December 27, 2006 9:32:24 PM (GMT Standard Time, UTC+00:00)
I'm actively using it at work with VFP9. Having come from a VB background, I was surprised to learn that there was no native Regular Expression ability in Visual FoxPro. Your library has helped enormously! Would it be possible to add a documentation number to the FLL at some point? I run the risk of losing this web address and/or my own copy of your documentation when I leave the company :-(
All comments require the approval of the site owner before being displayed.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview

 

Archive

<August 2014>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456