Flype UserLibraries for PureBasic 4.0

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

Flype wrote:Here is a small example to introduce PureXML2.

This shows how to very easily retrieves partial informations
from a distant XML document using ParseUrl() and the CharacterData handler.

Code: Select all

Global result$

Procedure.l Extract_From_IpPages(name.s, string.s, length.l)
  
  Select name ; tag name
    Case "ip":      result$ + "IP V4: " + #TAB$ + string + #CRLF$
    Case "ip_long": result$ + "IP: "    + #TAB$ + string + #CRLF$
    Case "ipv6":    result$ + "IP V6: " + #TAB$ + string + #CRLF$
    Case "host":    result$ + "HOST: "  + #TAB$ + string + #CRLF$
    Case "isp":     result$ + "ISP: "   + #TAB$ + string + #CRLF$
    Case "country": result$ + "CTRY: "  + #TAB$ + string + #CRLF$
  EndSelect
  
EndProcedure

If MessageRequester("Question", "Resolves your IP Address from `ippages.com` ?", #MB_OKCANCEL|#MB_ICONQUESTION) = #IDOK
  
  PureXML_SetCharacterDataHandler(@Extract_From_IpPages())
  
  If PureXML_ParseUrl("http://www.ippages.com/xml/")
    
    If MessageRequester("Copy the result to the clipboard ?", result$, #MB_OKCANCEL|#MB_ICONINFORMATION) = #IDOK
      
      SetClipboardText(result$)
      
    EndIf
    
  Else
    
    MessageRequester("Error", PureXML_GetErrorString(), #MB_ICONERROR)
    
  EndIf
  
EndIf
This is a very practical way to parse XML files. Similar approach is also used in perl. Thank you very much for making this library available for Purebasic community. I'll be using it very much and believe it's a heaven-sent library for many developers.

-davenull-
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

thank you davenull, nice to you.

i hope it will useful for many developpers.

i need volonteers for beta testing, writing full examples...
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

Flype wrote:thank you davenull, nice to you.

i hope it will useful for many developpers.

i need volonteers for beta testing, writing full examples...
I'll test this library starting tomorrow and post my experiences here.

-davenull-
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

I'll test this library starting tomorrow and post my experiences here.
It's been a busy day, so only little testing has been possible.

I tried to parse an xml file with an empty value and the parser didn't detect it.


Here's the test code:

Code: Select all

Macro PrintXMLData(xml_tag)
  If tagname = xml_tag
    If chardata = ""
        Debug "Empty!"
      Else
        Debug chardata
      EndIf
  EndIf
EndMacro

Procedure ProductInfo(tagname.s, chardata.s, length.l)
  PrintXMLData("name")
  PrintXMLData("price")  
  PrintXMLData("desc")
EndProcedure

PureXML_SetCharacterDataHandler(@ProductInfo())

PureXML_ParseFile("products.xml")
And this is the xml file (products.xml):

<?xml version="1.0" encoding="ISO-8859-1"?>

<products>
<product>
<name>gizmo</name>
<price>50</price>
<desc>for geeks</desc>
</product>
<product>
<name>gadget</name>
<price>10</price>
<desc>for programmers</desc>
</product>
<product>
<name>utility</name>
<price>99</price>
<desc></desc>
</product>
</products>


The description (<desc></desc>) of the last product is empty, so the debug line should read "Empty!". It doesn't print anything, however. Is this the way it should be or how to detect the empty values?

-davenull-
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

The CharacterData Handler isn't called if there's no data to transmit, so the behaviour is normal in my opinion.

The easier way in your case (and many others cases) is to catch the data you want once the tag is closed which means totally parsed (open-chardata-close).

i'll prepare you an example right now.
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Code: Select all

Procedure ProductInfo(name.s, depth.l)
  
  Protected chardata.s
  
  Select name
    
    Case "name", "price", "desc"
      
      chardata = PureXML_GetCharData()
      
      If Trim(chardata)
        Debug name + " = " + chardata
      Else
        Debug name + " = Empty !"
      EndIf
      
    Case "product"
      
      Debug ""
      
  EndSelect
  
EndProcedure

PureXML_SetCloseHandler(@ProductInfo())

PureXML_ParseFile("products.xml")
Last edited by Flype on Tue Jan 16, 2007 8:44 pm, edited 1 time in total.
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Here is a full example that shows how to add all your Products in a LinkedList ready for classic processing :

xml$ + "<?xml version='1.0'?>"
xml$ + "<products>"
xml$ + " <product id='PROD007'>"
xml$ + " <name>gizmo</name>"
xml$ + " <price>50</price>"
xml$ + " <desc>for geeks</desc>"
xml$ + " </product>"
xml$ + " <product id='PROD008'>"
xml$ + " <name>gadget</name>"
xml$ + " <price>10</price>"
xml$ + " <desc>for programmers</desc>"
xml$ + " </product>"
xml$ + " <product id='PROD009'>"
xml$ + " <name>utility</name>"
xml$ + " <price>99</price>"
xml$ + " <desc></desc>"
xml$ + " </product>"
xml$ + "</products>"

Code: Select all

Structure PRODUCT
  id.s
  name.s
  price.s
  desc.s
EndStructure

Global NewList product.PRODUCT()

Procedure ProductInfo_StartElement(name.s, depth.l)
  
  If name = "product"
    If AddElement(product())
      product()\id = PureXML_GetAttr("id")
    EndIf
  EndIf
  
EndProcedure

Procedure ProductInfo_EndElement(name.s, depth.l)
  
  Select name
    Case "name":  product()\name  = PureXML_GetCharData()
    Case "price": product()\price = PureXML_GetCharData()
    Case "desc":  product()\desc  = PureXML_GetCharData()
  EndSelect
  
EndProcedure

PureXML_SetElementHandler(@ProductInfo_StartElement(), @ProductInfo_EndElement())

If PureXML_ParseString(xml$) 
  ForEach product()
    Debug "id = "    + product()\id
    Debug "name = "  + product()\name
    Debug "price = " + product()\price
    Debug "desc = "  + product()\desc
    Debug ""
  Next
EndIf
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

Flype wrote:Here is a full example that shows how to add all your Products in a LinkedList ready for classic processing :

xml$ + "<?xml version='1.0'?>"
xml$ + "<products>"
xml$ + " <product id='PROD007'>"
xml$ + " <name>gizmo</name>"
xml$ + " <price>50</price>"
xml$ + " <desc>for geeks</desc>"
xml$ + " </product>"
xml$ + " <product id='PROD008'>"
xml$ + " <name>gadget</name>"
xml$ + " <price>10</price>"
xml$ + " <desc>for programmers</desc>"
xml$ + " </product>"
xml$ + " <product id='PROD009'>"
xml$ + " <name>utility</name>"
xml$ + " <price>99</price>"
xml$ + " <desc></desc>"
xml$ + " </product>"
xml$ + "</products>"

Code: Select all

Structure PRODUCT
  id.s
  name.s
  price.s
  desc.s
EndStructure

Global NewList product.PRODUCT()

Procedure ProductInfo_StartElement(name.s, depth.l)
  
  If name = "product"
    If AddElement(product())
      product()\id = PureXML_GetAttr("id")
    EndIf
  EndIf
  
EndProcedure

Procedure ProductInfo_EndElement(name.s, depth.l)
  
  Select name
    Case "name":  product()\name  = PureXML_GetCharData()
    Case "price": product()\price = PureXML_GetCharData()
    Case "desc":  product()\desc  = PureXML_GetCharData()
  EndSelect
  
EndProcedure

PureXML_SetElementHandler(@ProductInfo_StartElement(), @ProductInfo_EndElement())

If PureXML_ParseString(xml$) 
  ForEach product()
    Debug "id = "    + product()\id
    Debug "name = "  + product()\name
    Debug "price = " + product()\price
    Debug "desc = "  + product()\desc
    Debug ""
  Next
EndIf
Very nice, thanks. This method is quite usable.

-davenull-
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Code: Select all

Procedure ProductInfo_EndElement(name.s, depth.l)
 
  Select name
    Case "name":  product()\name  = PureXML_GetCharData()
    Case "price": product()\price = PureXML_GetCharData()
    Case "desc":  product()\desc  = PureXML_GetCharData()
  EndSelect
 
EndProcedure
i think i will add PureXML_GetCharData() directly in the argument list (in the EndElement handler.
so that it might be easier to process the chardata - perhaps faster :

Code: Select all

Procedure ProductInfo_EndElement(name.s, chardata.s, length.l, depth.l)
 
  Select name
    Case "name":  product()\name  = chardata
    Case "price": product()\price = chardata
    Case "desc":  product()\desc  = chardata
  EndSelect
 
EndProcedure
in the next beta4...
and i'm not sure that the 'depth.l' argument is really useful - should i remove it ?
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

Flype wrote:

Code: Select all

Procedure ProductInfo_EndElement(name.s, depth.l)
 
  Select name
    Case "name":  product()\name  = PureXML_GetCharData()
    Case "price": product()\price = PureXML_GetCharData()
    Case "desc":  product()\desc  = PureXML_GetCharData()
  EndSelect
 
EndProcedure
i think i will add PureXML_GetCharData() directly in the argument list (in the EndElement handler.
so that it might be easier to process the chardata - perhaps faster :

Code: Select all

Procedure ProductInfo_EndElement(name.s, chardata.s, length.l, depth.l)
 
  Select name
    Case "name":  product()\name  = chardata
    Case "price": product()\price = chardata
    Case "desc":  product()\desc  = chardata
  EndSelect
 
EndProcedure
in the next beta4...
and i'm not sure that the 'depth.l' argument is really useful - should i remove it ?
IMHO, it could be useful to have the 'depth.l' argument, since there could be tags with the same name in different depths.

Are you planning to include the namespace support in the library?

-davenull-
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

ok i keep the 'depth' argument.

by 'namespace' you means DTD ?

i'm not familiar at all with namespace - can you explain a bit more ?

but it should be added soon because the Expat library support it.
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

Flype wrote:ok i keep the 'depth' argument.

by 'namespace' you means DTD ?

i'm not familiar at all with namespace - can you explain a bit more ?

but it should be added soon because the Expat library support it.
Thanks for enhancing the lib.

W3schools.com offers a nice explanation about namespaces:
http://www.w3schools.com/xml/xml_namespaces.asp

So it might come handy sometimes to have namespaces supported. A nice feature of a event-driven parser is that there's no need to obey a DTD or an XML Schema :D

-davenull-
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

ASCII

Post by davenull »

Does the current lib support US-ASCII only or also extensions like ISO 8859-1? I was parsing was a tag with an character > 127 in ASCII table (ö) and that didn't work.

-davenull-
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Yes, there is the PureXML_SetEncoding(encoding.s) which should be initialized before calling PureXML_ParseFile().

It should works.


[edit] thank you the link about namespace - i will take a closer look.
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
davenull
User
User
Posts: 25
Joined: Sat Sep 17, 2005 5:31 pm
Location: Finland

Post by davenull »

Flype wrote:Yes, there is the PureXML_SetEncoding(encoding.s) which should be initialized before calling PureXML_ParseFile().

It should works.


[edit] thank you the link about namespace - i will take a closer look.
Unfortunately I can't get it working. Here's the code you posted earlier with a minor change (gizmo --> gizmö) and of course PureXML_SetEncoding("ISO-8859-1").

Code: Select all

xml$ + "<?xml version='1.0'?>"
xml$ + "<products>"
xml$ + " <product id='PROD007'>"
xml$ + " <name>gizmö</name>"
xml$ + " <price>50</price>"
xml$ + " <desc>for geeks</desc>"
xml$ + " </product>"
xml$ + " <product id='PROD008'>"
xml$ + " <name>gadget</name>"
xml$ + " <price>10</price>"
xml$ + " <desc>for programmers</desc>"
xml$ + " </product>"
xml$ + " <product id='PROD009'>"
xml$ + " <name>utility</name>"
xml$ + " <price>99</price>"
xml$ + " <desc></desc>"
xml$ + " </product>"
xml$ + "</products>"

Structure PRODUCT
  id.s
  name.s
  price.s
  desc.s
EndStructure

Global NewList product.PRODUCT()

Procedure ProductInfo_StartElement(name.s, depth.l)
  
  If name = "product"
    If AddElement(product())
      product()\id = PureXML_GetAttr("id")
    EndIf
  EndIf
  
EndProcedure

Procedure ProductInfo_EndElement(name.s, depth.l)
  
  Select name
    Case "name": product()\name = PureXML_GetCharData()
    Case "price": product()\price = PureXML_GetCharData()
    Case "desc": product()\desc = PureXML_GetCharData()
  EndSelect
  
EndProcedure

PureXML_SetEncoding("ISO-8859-1")
PureXML_SetElementHandler(@ProductInfo_StartElement(), @ProductInfo_EndElement())

If PureXML_ParseString(xml$)
  ForEach product()
    Debug "id = " + product()\id
    Debug "name = " + product()\name
    Debug "price = " + product()\price
    Debug "desc = " + product()\desc
    Debug ""
  Next
EndIf
It doesn't return an 'o' with umlaut, but rather a capital 'A' with a tilde above plus a paragraph sign (Chr(182)).

Am I doing something wrong?

-davenull-
Post Reply