Page 6 of 9
					
				
				Posted: Mon Jan 15, 2007 3:14 pm
				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-
 
			 
			
					
				
				Posted: Mon Jan 15, 2007 3:32 pm
				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...
			 
			
					
				
				Posted: Mon Jan 15, 2007 3:38 pm
				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-
 
			 
			
					
				
				Posted: Tue Jan 16, 2007 3:34 pm
				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-
 
			 
			
					
				
				Posted: Tue Jan 16, 2007 8:21 pm
				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.
			 
			
					
				
				Posted: Tue Jan 16, 2007 8:31 pm
				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")
 
			 
			
					
				
				Posted: Tue Jan 16, 2007 8:42 pm
				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
 
			 
			
					
				
				Posted: Wed Jan 17, 2007 8:28 am
				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-
 
			 
			
					
				
				Posted: Wed Jan 17, 2007 9:09 am
				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 ?
 
			 
			
					
				
				Posted: Wed Jan 17, 2007 9:57 am
				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-
 
			 
			
					
				
				Posted: Wed Jan 17, 2007 10:47 am
				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.
			 
			
					
				
				Posted: Wed Jan 17, 2007 11:06 am
				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  
 
-davenull-
 
			 
			
					
				ASCII
				Posted: Wed Jan 17, 2007 11:28 am
				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-
			 
			
					
				
				Posted: Wed Jan 17, 2007 12:03 pm
				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.
			 
			
					
				
				Posted: Wed Jan 17, 2007 12:49 pm
				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-