Tuesday, July 26, 2005

OK, I've tried a number of different ways to get around handling additional elements that aren't in the RSS 2.0 specification (such as trackback:ping, wfw:rssComments, slash:comments, etc. - basically anything using QName).  First, I started with the way you are supposed to do it, referencing and importing namespaces, creating seperate xsd schemas and the using the ref attribute... that didn't work. So then I started hacking the document by adding the namespace to the elements of the XML on the fly, that didn't work either.

I've created a paired down version of my earlier schema (for testing purposes) that will grab the RSS 2.0 feed from the SPS Blog, but the hack is atrocious (look at the UndeclaredNamespace procedure). No matter what I try, I can't get MSXML4 and the XMLAdapter to behave and bring in those elements (with their content) without the hack. Anyone got any ideas, or better yet, solutions? I hope I'm missing something here and that it isn't a problem with MSXML4 with no workaround.

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

lcXMLHeader = GetHeader()
lcXSD = VFPRSS2Schema()
lcRSSContent = RetrieveRSS("
http://www.sweetpotatosoftware.com/SPSBlog/SyndicationService.asmx/GetRss")
UndeclaredNamespace(@lcRSSContent)
lcXMLFooter = GetFooter()

oXMLAdapter = NEWOBJECT('XMLAdapter')

oXMLAdapter.LOADXML(lcXMLHeader + lcXSD+ lcRSSContent + lcXMLFooter)

CLOSE DATABASES ALL
oXMLAdapter.TABLES(1).TOCURSOR && Item
oXMLAdapter.TABLES(2).TOCURSOR && Channel
oXMLAdapter.TABLES(3).TOCURSOR && Rss
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

*****************************
PROCEDURE UndeclaredNamespace(tcRSSContent)
*****************************
   *!* Workaround for MSXML4 - This needs to be worked on still, I can't seem to get these elements even if
   *!* I split up the schemas and use imports and ref in element tag
   *!* However, this workaround at least ensures that it doesn't blow up with "Undeclared Namespace Prefix" error
   *!* while still retrieving the contents. I hate hacks like this, especially in this case because these elements aren't
   *!* part of the specification, but are on many blogs including mine.
   *!* Anyone got a better fix or know how to do this right?
   tcRSSContent = STRTRAN(tcRSSContent, "trackback:ping", [trackbackping], -1, -1, 1)
   tcRSSContent = STRTRAN(tcRSSContent, "pingback:server", [pingbackserver], -1, -1, 1)
   tcRSSContent = STRTRAN(tcRSSContent, "pingback:target", [pingbacktarget], -1, -1, 1)
   tcRSSContent = STRTRAN(tcRSSContent, "wfw:commentRSS", [wfwcommentRss], -1, -1, 1)
   tcRSSContent = STRTRAN(tcRSSContent, "wfw:comment", [wfwcomment], -1, -1, 1)
   tcRSSContent = STRTRAN(tcRSSContent, "slash:comment>", [slashcomments], -1, -1, 1)
ENDPROC

*****************************
FUNCTION VFPRSS2Schema()
*****************************
 LOCAL lcXML
 TEXT TO lcXML NOSHOW
<xsd:schema xmlns:xsd="
http://www.w3.org/2001/XMLSchema"
   xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
   xmlns:trackback="
http://madskills.com/public/xml/rss/module/trackback/"
   xmlns:wfw="
http://wellformedweb.org/CommentAPI/"
   xmlns:slash="
http://purl.org/rss/1.0/modules/slash/"
   xmlns:pingback="
http://madskills.com/public/xml/rss/module/pingback/"
  attributeFormDefault="qualified" elementFormDefault="qualified" >
  <xsd:element name="rss">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="channel">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="title" type="xsd:string" />
              <xsd:element name="link" type="xsd:string" />
              <xsd:element name="description" type="xsd:string" />
              <xsd:element name="copyright" type="xsd:string" />
              <xsd:element name="lastBuildDate" type="xsd:string" />
              <xsd:element name="generator" type="xsd:string" />
              <xsd:element name="managingEditor" type="xsd:string" />
              <xsd:element name="webMaster" type="xsd:string" />
              <xsd:element name="item">
                <xsd:complexType>
                  <xsd:sequence>
                     <xsd:element name="trackbackping" type="xsd:string" maxOccurs="unbounded" />
                     <xsd:element name="pingserver" type="xsd:string" />
                    <xsd:element name="pingtarget" type="xsd:string" />
                    <xsd:element name="wfwcomment" type="xsd:string" />
                    <xsd:element name="wfwcommentRss" type="xsd:string" />
                    <xsd:element name="slashcomments" type="xsd:string" />
                    <xsd:element name="title" type="xsd:string" />
                    <xsd:element name="guid" type="xsd:string" />
                    <xsd:element name="link" type="xsd:string" />
                    <xsd:element name="pubDate" type="xsd:string" />
                    <xsd:element name="description" type="xsd:string" />
                    <xsd:element name="comments" type="xsd:string" />
                    <xsd:element name="category" type="xsd:string" />
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
      <xsd:attribute name="version" type="xsd:decimal" use="required" />
    </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("<rss", lcRetVal))
   
   RETURN LEFT(lcRetVal, ATC("</rss>", lcRetVal) + 9)
  ENDIF
 ENDIF
 RETURN ""
ENDFUNC

Tuesday, July 26, 2005 11:02:55 AM (Central Daylight Time, UTC-05:00)  #    Comments [0]
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, super, u)  

Enter the code shown (prevents robots):


 

Archive

<August 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456