Author Topic: ScriptBasic Mini-XML Extension Module  (Read 4431 times)

Offline John

  • Forum Support / SB Dev
  • Posts: 3004
    • ScriptBasic Open Source Project
ScriptBasic Mini-XML Extension Module
« on: April 10, 2011, 04:11:02 PM »
Mini-XML is a small XML library that you can use to read and write XML and XML-like data files in your application without requiring large non-standard libraries.

Armando created the mxml extension module as a replacement for the GNOME libxml2 extension module that was introduced with the 2.0 release by Peter Verhas but never fully tested or documented.

Code: [Select]
include mxml.bas

filename = "stuff.xml"
doc = mxml::LoadDoc(filename)

node =  mxml::GetNode(doc,"/stufflist/stuff_test")
if node then print "Test1: ", mxml::GetNodeValue(node),"\n"
node =  mxml::GetNode(doc,"/stufflist/stuff_test2")
if (node) then print "Test2: ", mxml::GetNodeValue(node),"\n\n"

node = mxml::GetNode(doc,"/stufflist/stuff_test3/painting/img")
if node then
print "Image: ", mxml::GetProperty(node,"src"), "\n"
print "Alt Image: ", mxml::GetProperty(node,"alt"), "\n\n"
endif

node = mxml::GetNode(doc,"/stufflist/books")
child = mxml::GetChild(node)

while child
node = mxml::GetNode(child,"id")
if node then print "ID = ", mxml::GetNodeValue(node),"\n"
node = mxml::GetNode(child,"name")
if node then print "Name = ", mxml::GetNodeValue(node),"\n"
child = mxml::GetNext(child)
wend

if doc then mxml::FreeDoc(doc)

Code: Text
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <stufflist>
  3.         <stuff_test>This is a test!</stuff_test>
  4.         <stuff_test2>And this is another test!</stuff_test2>
  5.         <stuff_test3>
  6.                 <painting>
  7.                         <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  8.                         <caption>This is Raphael's "Foligno" Madonna, painted in
  9.                                 <date>1511</date>.
  10.                         </caption>
  11.                 </painting>
  12.         </stuff_test3>
  13.         <books>
  14.     <book>
  15.         <id>1</id>
  16.         <name>Hello, world!</name>
  17.     </book>
  18.     <book>
  19.         <id>2</id>
  20.         <name>Hello, China!</name>
  21.     </book>
  22.         </books>
  23. </stufflist>
  24.  

jrs@Laptop:~/SB/test$ scriba mxmltest.sb
Test1: This is a test!
Test2: And this is another test!

Image: madonna.jpg
Alt Image: Foligno Madonna, by Raphael

ID = 1
Name = Hello, world!
ID = 2
Name = Hello, China!
jrs@Laptop:~/SB/test$

LoadDoc - Load an XML file and read into memory

You should use this function to read the content of an XML file into memory.
The argument of the function is the name of the file to be read. The function
will return a handle to the structure created during the parsing of the file
content.
DOC = mxml::LoadDoc("my_file.xml")


GetNext - Get the next node of a document node

This function should be used to get the handle to the  next node in a
document node
node = mxml::GetNext(<node pointer>)


GetChild - Get the next Child node of a document node

This function should be used to get the handle to the next Childe node of a
document node
node = mxml::GetChild(<node pointer>)


GetNodeValue - Get the value of a document node

This function should be used to get the value (text) of a node
text = mxml::GetNodeValue(<node pointer>)


GetProperty - Get the a property value of a document node

This function should be used to get the
value of a property of a document node
text = mxml:: mxml::GetProperty(<node pointer>,<string identifier>)


GetNode - Get a handle to a specified node

This function should be used to get the handle of a specific node.
It uses XPATH syntax, which resembles a UNIX path.
node = mxml::GetNode(<node pointer>,<path-like string>)


SaveDoc - Save to an XML file

This function should be used to save the contents of an XML tree
to a disk file
mxml::SaveDoc(<DOC (root) node pointer>,<string filename>)


NewDoc - Create a new XML document in memory

This function should be used to create a new XML document in memory.

The second parameter (xml version) is optional.  If not provided,
it defaults to version="1.0"

It would create a header that looks like:
   <?xml version="1.0">

doc = mxml::NewDoc(<string version>)


FreeDoc - Releases/Destroys an XML tree in memory

This function should be used to delete an new XML document in memory.
mxml::FreeDoc(<doc pointer>)


The attached mxml_i386.tar.gz is for 32 bit versions of Linux.
« Last Edit: April 10, 2011, 09:21:41 PM by ABB »

Offline John

  • Forum Support / SB Dev
  • Posts: 3004
    • ScriptBasic Open Source Project
Re: ScriptBasic Mini-XML Extension Module
« Reply #1 on: April 12, 2011, 07:10:24 PM »
Here is the 64 bit version of the Mini-XML extension module for Linux. I have included the compiled shared object (mxml.so), the source from Armando and his example program.

Offline John

  • Forum Support / SB Dev
  • Posts: 3004
    • ScriptBasic Open Source Project
Re: ScriptBasic Mini-XML Extension Module
« Reply #2 on: April 12, 2011, 08:08:08 PM »
The Mini-XML API isn't fully implemented in the ScriptBasic mxml extension module. If you find this interface of value and would be willing to contribute by expanding it, please reply here and indicate your willingness to help the project out.


Mini-XML API
mxmlAdd
mxmlDelete
mxmlElementDeleteAttr
mxmlElementGetAttr
mxmlElementSetAttr
mxmlElementSetAttrf
mxmlEntityAddCallback
mxmlEntityGetName
mxmlEntityGetValue
mxmlEntityRemoveCallback
mxmlFindElement
mxmlIndexDelete
mxmlIndexEnum
mxmlIndexFind
mxmlIndexNew
mxmlIndexReset
mxmlLoadFd
mxmlLoadFile
mxmlLoadString
mxmlNewCDATA
mxmlNewCustom
mxmlNewElement
mxmlNewInteger
mxmlNewOpaque
mxmlNewReal
mxmlNewText
mxmlNewTextf
mxmlNewXML
mxmlRelease
mxmlRemove
mxmlRetain
mxmlSAXLoadFd
mxmlSAXLoadFile
mxmlSAXLoadString
mxmlSaveAllocString
mxmlSaveFd
mxmlSaveFile
mxmlSaveString
mxmlSetCDATA
mxmlSetCustom
mxmlSetCustomHandlers
mxmlSetElement
mxmlSetErrorCallback
mxmlSetInteger
mxmlSetOpaque
mxmlSetReal
mxmlSetText
mxmlSetTextf
mxmlSetWrapMargin
mxmlWalkNext
mxmlWalkPrev

ScriptBasic extension module interface
declare sub     ::LoadDoc      alias "LoadDoc"      lib "mxml"
declare sub     ::GetNext      alias "GetNext"      lib "mxml"
declare sub     ::GetChild     alias "GetChild"     lib "mxml"
declare sub     ::GetNodeValue alias "GetNodeValue" lib "mxml"
declare sub     ::GetProperty  alias "GetProperty"  lib "mxml"
declare sub     ::GetNode      alias "GetNode"      lib "mxml"
declare sub     ::SaveDoc      alias "SaveDoc"      lib "mxml"
declare sub     ::NewDoc       alias "NewDoc"       lib "mxml"
declare sub     ::FreeDoc      alias "FreeDoc"      lib "mxml"

Mini-XML functions used by ScriptBasic
mxmlLoadFile
mxmlElementGetAttr
mxmlFindElement
mxmlSaveFile
mxmlNewXML
mxmlDelete

mxml ScriptBasic interface.c
Code: [Select]
/*

Mini-XML Support code for Scriptbasic

Copyright 2010, Armando I. Rivera, Recursive Media Group.

Released under the terms of the Mini-Xml Licence.

The Mini-XML library and included programs are provided under the terms of the
GNU Library General Public License (LGPL) with the following exceptions:

  1. Static linking of applications to the Mini-XML library does not constitute
a derivative work and does not require the author to provide source code for
the application, use the shared Mini-XML libraries, or link their applications
against a user-supplied version of Mini-XML.

  If you link the application to a modified version of Mini-XML, then the
changes to Mini-XML must be provided under the terms of the LGPL in sections
1, 2, and 4.

  2. You do not have to provide a copy of the Mini-XML license with programs
that are linked to the Mini-XML library, nor do you have to identify the
Mini-XML license in your program or documentation as required by section 6
of the LGPL.

  FILE   : interface.c
  HEADER : interface.h
  BAS    : mxml.bas
  AUTHOR : *TODO*

  DATE:

  CONTENT:
  This is the interface.c file for the ScriptBasic module xml

UXLIBS: -lmxml
DWLIBS: -lmxml

 */

#include <mxml.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../../basext.h"

typedef struct _ModuleObject {
  void *HandleArray;
}ModuleObject,*pModuleObject;

#define _MAX_PATH 4096

#define GET_ARGUMENT_POINTER(X,Y) \
  if( besARGNR < Y )return COMMAND_ERROR_ARGUMENT_RANGE;\
  Argument = besARGUMENT(Y);\
  besDEREFERENCE(Argument);\
  if( Argument == NULL )X=NULL; else { \
      if( Argument->vType != VTYPE_STRING ||\
          STRLEN(Argument) != sizeof(void *) ){\
    return COMMAND_ERROR_ARGUMENT_RANGE;\
    }\
  memcpy(&(X),STRINGVALUE(Argument),sizeof(void *));\
  }

#define RETURN_POINTER(X) \
  besALLOC_RETURN_STRING( sizeof( void *) );\
  memcpy(STRINGVALUE(besRETURNVALUE),&(X),sizeof(void *));



besVERSION_NEGOTIATE
  return (int)INTERFACE_VERSION;
besEND

besSUB_START
  pModuleObject p;

  besMODULEPOINTER = besALLOC(sizeof(ModuleObject));
  if( besMODULEPOINTER == NULL )return 0;

  p = (pModuleObject)besMODULEPOINTER;
  return 0;

besEND

besSUB_FINISH
  pModuleObject p;

  p = (pModuleObject)besMODULEPOINTER;
  if( p == NULL )return 0;
  return 0;
besEND

/**
=section LoadDoc
=H Load an XML file and read into memory

You should use this function to read the content of an XML file into memory.
The argument of the function is the name of the file to be read. The function
will return a handle to the structure created during the parsing of the file
content.

=verbatim
 DOC = mxml::LoadDoc("my_file.xml")
=noverbatim

*/
besFUNCTION(LoadDoc)
mxml_node_t *tree;
FILE *fp;
char *pszFileName;

besARGUMENTS("z")
    &pszFileName
  besARGEND

fp = fopen(pszFileName, "r");
  // check if file exists
  if(fp == NULL) {
      return NULL;
  }
   
  tree = mxmlLoadFile(NULL, fp, MXML_OPAQUE_CALLBACK);
fclose(fp);

  //besFREE(pszFileName);

  besRETURN_POINTER(tree);
besEND

/**
=section GetNext
=H Get the next node of a document node

This function should be used to get the handle to the  next node in a
document node

=verbatim
 node = mxml::GetNext(<node pointer>)
=noverbatim
*/
besFUNCTION(GetNext)
mxml_node_t *rootNode;

besARGUMENTS("p")
    &rootNode
  besARGEND

besRETURN_POINTER(rootNode->next);
besEND

/**
=section GetChild
=H Get the next Child node of a document node

This function should be used to get the handle to the next Childe node of a
document node

=verbatim
 node = mxml::GetChild(<node pointer>)
=noverbatim
*/
besFUNCTION(GetChild)
mxml_node_t *rootNode;

besARGUMENTS("p")
    &rootNode
  besARGEND

besRETURN_POINTER(rootNode->child);
besEND

/**
=section GetNodeValue
=H Get the value of a document node

This function should be used to get the value (text) of a node

=verbatim
 text = mxml::GetNodeValue(<node pointer>)
=noverbatim
*/
besFUNCTION(GetNodeValue)
mxml_node_t *rootNode;

besARGUMENTS("p")
    &rootNode
  besARGEND

besSET_RETURN_STRING(rootNode->child->value.opaque);
besEND

/**
=section GetProperty
=H Get the a property value of a document node

This function should be used to get the
value of a property of a document node

=verbatim
 text = mxml:: mxml::GetProperty(<node pointer>,<string identifier>)
=noverbatim
*/
besFUNCTION(GetProperty)
mxml_node_t* node;
const char* attr;
char* pszValue;

besARGUMENTS("pz")
    &node,&attr
  besARGEND

pszValue = mxmlElementGetAttr(node, attr);

besSET_RETURN_STRING(pszValue);
besEND

/**
=section GetNode
=H Get a handle to a specified node

This function should be used to get the handle of a specific node.
It uses XPATH syntax, which resembles a UNIX path.

Ex, node = mxml::GetNode(doc, "/stufflist/stuff_test3/painting/img")

=verbatim
 node = mxml::GetNode(<node pointer>,<path-like string>)
=noverbatim
*/
besFUNCTION(GetNode)
mxml_node_t *rootNode, *node;
char *pszValue;
char *token, tmpStr[_MAX_PATH];

besARGUMENTS("pz")
    &rootNode,&pszValue
  besARGEND

node = rootNode;

memset(tmpStr,0,sizeof(tmpStr));
strncpy(tmpStr, pszValue, strlen(pszValue));


token = strtok(tmpStr, "/");
  while ( token  ) {
node = mxmlFindElement(node,node,token,NULL,NULL,MXML_DESCEND);
    token = strtok( NULL, "/" );
  }

besRETURN_POINTER(node);
besEND

/**
=section SaveDoc
=H Save to an XML file

This function should be used to save the contents of an XML tree
to a disk file

=verbatim
 mxml::SaveDoc(<DOC (root) node pointer>,<string filename>)
=noverbatim
*/
besFUNCTION(SaveDoc)
mxml_node_t* node;
const char* fileName;
FILE *fp;
int retVal;

besARGUMENTS("pz")
    &node,&fileName
  besARGEND

fp = fopen(fileName, "w");
  if(fp == NULL) {
    besRETURN_LONG(-1);
  }

retVal = mxmlSaveFile(node, fp, MXML_NO_CALLBACK);
fclose(fp);
besRETURN_LONG(retVal);
besEND

/**
=section NewDoc
=H Create a new XML document in memory

This function should be used to create a new XML document in memory.

The second parameter (xml version) is optional.  If not provided,
it defaults to version="1.0"

It would create a header that looks like:
<?xml version="1.0">

=verbatim
 doc = mxml::NewDoc(<string version>)
=noverbatim
*/
besFUNCTION(NewDoc)
mxml_node_t* node;
char* pszVersion;


besARGUMENTS("[z]")
    &pszVersion
  besARGEND

node = mxmlNewXML(pszVersion);
besRETURN_POINTER(node);

besEND

/**
=section FreeDoc
=H Releases/Destroys an XML tree in memory

This function should be used to delete an new XML document in memory.

=verbatim
 mxml::FreeDoc(<doc pointer>)
=noverbatim
*/
besFUNCTION(FreeDoc)
mxml_node_t* node;

besARGUMENTS("p")
    &node
  besARGEND

if (node) mxmlDelete(node);
besEND


/*
Exported Function List
*/
SLFST XML_SLFST[] ={

{ "versmodu" , versmodu },
{ "bootmodu" , bootmodu },
{ "finimodu" , finimodu },
{ "LoadDoc" , LoadDoc },
{ "GetNext" , GetNext },
{ "GetChild" , GetChild },
{ "GetNodeValue", GetNodeValue },
{ "GetNode" , GetNode },
{ "SaveDoc" , SaveDoc },
{ "NewDoc" , NewDoc },
{ "FreeDoc" , FreeDoc },
{ "GetProperty", GetProperty },
{ NULL , NULL }
  };
« Last Edit: April 12, 2011, 08:35:42 PM by ABB »

Offline John

  • Forum Support / SB Dev
  • Posts: 3004
    • ScriptBasic Open Source Project
Re: ScriptBasic Mini-XML Extension Module
« Reply #3 on: April 15, 2011, 10:38:03 AM »
I could use this library with my MLS application and parsing code conversion XML responses but it would be nice if I could pass mxml a string of XML rather than having to load a file.

Code: [Select]
mxmlLoadString

Load a string into an XML node tree.

mxml_node_t *mxmlLoadString (
    mxml_node_t *top,
    const char *s,
    mxml_load_cb_t cb
);

Is one of the existing mxml functions close enough I could use it as an example to add this function?