Ken Levy mentioned out on the UT yesterday that it would be a cool VFP open source project to create a table that RSS could be imported into and the exported out of. I thought it was an excellent idea. So, I played around with RSS 2.0 last night. After more than a little reading on the specifications for RSS 2.0, and some trial and error, I was able to create a workable XML schema (XSD) for RSS 2.0. When I say workable, I mean I wanted it to work with VFP’s XMLAdapter class. I’ll be working on the other RSS schemas as time permits.


Below is a runnable example using the new schema and pulling RSS 2.0 sample content from:
http://media-cyber.law.harvard.edu/blogs/gems/tech/rss2sample.xml


It’s a lot of code, but most of it is the XML schema, and that could be placed in a file to be used as the XMLAdapter’s schema. I just wanted to provide an example here that runs right out of the box with a copy of VFP 9 and an internet connetction. Have fun! (I’ll quit getting side-tracked and get back to Emal and VFP shortly)







LOCAL loXMLAdapter, loBrowser, lcXSD, lcRSSContent, lcXMLHeader, lcXMLFooter


lcXMLHeader = GetHeader()
lcXSD = VFPRSS2Schema()
lcRSSContent = RetrieveRSS(“
http://media-cyber.law.harvard.edu/blogs/gems/tech/rss2sample.xml“)
lcXMLFooter = GetFooter()


oXMLAdapter = NEWOBJECT(‘XMLAdapter’)
oXMLAdapter.LOADXML(lcXMLHeader + lcXSD + lcRSSContent + lcXMLFooter)


CLOSE DATABASES ALL
oXMLAdapter.TABLES(1).TOCURSOR && Cloud
oXMLAdapter.TABLES(2).TOCURSOR && Image
oXMLAdapter.TABLES(3).TOCURSOR && Textinput
oXMLAdapter.TABLES(4).TOCURSOR && Enclosure
oXMLAdapter.TABLES(5).TOCURSOR && Item
oXMLAdapter.TABLES(6).TOCURSOR && Channel
SET


*****************************
FUNCTION GetHeader()
*****************************
 LOCAL lcHeader
 TEXT TO lcHeader NOSHOW
<?xml version=”1.0″ encoding=”utf-8″ ?>
<VFPDataSet>
 ENDTEXT
 RETURN lcHeader
ENDFUNC


*****************************
FUNCTION GetFooter()
*****************************
 LOCAL lcFooter
 TEXT TO lcFooter NOSHOW
</VFPDataSet>
 ENDTEXT
 RETURN lcFooter
ENDFUNC


*****************************
FUNCTION VFPRSS2Schema()
*****************************
 LOCAL lcXML
 TEXT TO lcXML NOSHOW
<xsd:schema id=”VFPDataSet” xmlns:xsd=”
http://www.w3.org/2001/XMLSchema” xmlns:msdata=”urn:schemas-microsoft-com:xml-msdata”>
 <xsd:element name=”VFPDataSet” msdata:IsDataSet=”true”>
  <xsd:complexType>
   <xsd:choice maxOccurs=”unbounded”>
   <xsd:element name=”channel”>
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name=”title” minOccurs=”1″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”link” minOccurs=”1″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”description” minOccurs=”1″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”language” minOccurs=”0″ maxOccurs=”1″  default=”en-us”>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”copyright” minOccurs=”0″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”managingEditor” minOccurs=”0″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”webMaster” minOccurs=”0″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”pubDate” minOccurs=”0″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”lastBuildDate” minOccurs=”0″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”category” minOccurs=”0″ maxOccurs=”unbounded”>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”generator” minOccurs=”0″ maxOccurs=”1″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”docs” default=”
http://blogs.law.harvard.edu/tech/rss“>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”cloud”>
       <xsd:complexType>
        <xsd:sequence>
         <xsd:element name=”domain” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:string”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”port” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:integer”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”path” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:string”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”registerProcedure” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:string”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”protocol” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:string”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
        </xsd:sequence>
       </xsd:complexType>
      </xsd:element>
      <xsd:element name=”ttl”>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:integer”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”image”>
       <xsd:complexType>
        <xsd:sequence>
         <xsd:element name=”url” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:anyURI”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”title” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:string”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”link” minOccurs=”1″ maxOccurs=”1″>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:anyURI”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”width” default=”88″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:decimal”>
            <xsd:maxInclusive value=”144″></xsd:maxInclusive>
            <xsd:minInclusive value=”0″></xsd:minInclusive>
            <xsd:fractionDigits value=”0″></xsd:fractionDigits>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”height” default=”31″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:decimal”>
            <xsd:maxInclusive value=”400″></xsd:maxInclusive>
            <xsd:minInclusive value=”0″></xsd:minInclusive>
            <xsd:fractionDigits value=”0″></xsd:fractionDigits>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”description”>
           <xsd:simpleType>
            <xsd:restriction base=”xsd:anyURI”>
            </xsd:restriction>
           </xsd:simpleType>
         </xsd:element>
        </xsd:sequence>
       </xsd:complexType>
      </xsd:element>
      <xsd:element name=”rating”>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”textInput”>
       <xsd:complexType>
        <xsd:sequence>
         <xsd:element name=”title”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”description”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”name”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”link”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:anyURI”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
        </xsd:sequence>
       </xsd:complexType>
      </xsd:element>
      <xsd:element name=”skipHours” minOccurs=”0″ maxOccurs=”24″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”skipDays” minOccurs=”0″ maxOccurs=”7″>
       <xsd:simpleType>
        <xsd:restriction base=”xsd:string”>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name=”item”>
       <xsd:complexType>
        <xsd:sequence>
         <xsd:element name=”title”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”link”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”description”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”author” minOccurs=”0″ maxOccurs=”1″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”category” minOccurs=”0″ maxOccurs=”unbounded”>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”comments” minOccurs=”0″ maxOccurs=”1″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:anyURI”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”enclosure”>
          <xsd:complexType>
           <xsd:sequence>
            <xsd:element name=”url” minOccurs=”1″ maxOccurs=”1″>
             <xsd:simpleType>
              <xsd:restriction base=”xsd:anyURI”>
              </xsd:restriction>
             </xsd:simpleType>
            </xsd:element>
            <xsd:element name=”length” minOccurs=”1″ maxOccurs=”1″>
             <xsd:simpleType>
              <xsd:restriction base=”xsd:integer”>
              </xsd:restriction>
             </xsd:simpleType>
            </xsd:element>
            <xsd:element name=”type” minOccurs=”1″ maxOccurs=”1″>
             <xsd:simpleType>
              <xsd:restriction base=”xsd:string”>
              </xsd:restriction>
             </xsd:simpleType>
            </xsd:element>
           </xsd:sequence>
          </xsd:complexType>
         </xsd:element>
         <xsd:element name=”guid” minOccurs=”0″ maxOccurs=”1″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
           <!–
            <xsd:attribute name=”isPermaLink” type=”xs:boolean” default=”true”></xsd:attribute>
           –>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”pubDate” minOccurs=”0″ maxOccurs=”1″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
         <xsd:element name=”source” minOccurs=”0″ maxOccurs=”1″>
          <xsd:simpleType>
           <xsd:restriction base=”xsd:string”>
           </xsd:restriction>
          </xsd:simpleType>
         </xsd:element>
        </xsd:sequence>
       </xsd:complexType>
      </xsd:element>
     </xsd:sequence>
    <xsd:attribute name=”version” default=”2.0″></xsd:attribute>
    </xsd:complexType>
   </xsd:element>
   </xsd:choice>
  </xsd:complexType>
 </xsd:element>
</xsd:schema>
 ENDTEXT
 RETURN lcXML
ENDFUNC


*****************************
FUNCTION RetrieveRSS(tcURL)
*****************************
 #DEFINE INTERNET_OPEN_TYPE_PRECONFIG 0
 #DEFINE SYNCHRONOUS 0
 #DEFINE INTERNET_FLAG_RELOAD 2147483648


 DECLARE INTEGER InternetOpen IN WININET STRING Agent, ;
  INTEGER AccessType, STRING ProxyName, ;
  STRING ProxyBypass, INTEGER Flags


 DECLARE INTEGER InternetOpenUrl IN WININET ;
  INTEGER hInternetSession, STRING Url, STRING Header, ;
  INTEGER HeaderLength, INTEGER Flags, INTEGER Context


 DECLARE INTEGER InternetReadFile IN WININET INTEGER file, ;
  STRING @Buffer, INTEGER NumberOfBytesToRead, INTEGER @BytesRead


 DECLARE SHORT InternetCloseHandle IN WININET INTEGER hInst


 LOCAL lcAgent, lhInternetSession, lhFile, llOK, lnReturn, lcReadBuffer, lnBytesRead, lcRetVal


 lcAgent = “VFP RSS 2.0 Reader”
 lhInternetSession = InternetOpen(lcAgent, INTERNET_OPEN_TYPE_PRECONFIG, “”, “”, SYNCHRONOUS)


 IF lhInternetSession = 0
  ? “Problem Encountered: Internet session cannot be established”
 ELSE
  lhFile = InternetOpenUrl( lhInternetSession, tcURL, ”, 0, INTERNET_FLAG_RELOAD, 0)
  IF lhFile = 0
   ? “Problem Encountered: URL cannot be opened”
  ELSE
   lcRetVal = “”
   llOK = .T.
   
   DO WHILE llOK
    lcReadBuffer = SPACE(1500)
    lnBytesRead = 0
    lnReturn = InternetReadFile(lhFile, @lcReadBuffer, LEN(lcReadBuffer), @lnBytesRead)
    IF (lnBytesRead > 0)
     lcRetVal = lcRetVal + LEFT(lcReadBuffer, lnBytesRead)
    ENDIF
    llOK = (lnReturn = 1 AND lnBytesRead > 0)
   ENDDO
   
   InternetCloseHandle(lhFile)
   InternetCloseHandle(lhInternetSession)
   lcRetVal = SUBSTR(lcRetVal, ATC(“<channel”, lcRetVal))
   
   RETURN LEFT(lcRetVal, ATC(“</channel>”, lcRetVal) + 9)
  ENDIF
 ENDIF
 RETURN “”
ENDFUNC

UPDATES: Fixed malformed html in entry