If you have found this page, there is a good chance you have been searching for an example of how to use the XML library that is not well documented for use in MapBasic.
In this example I will show you how to read an XML file using Xpath and the XMLlib library in MapBasic. Currently the XMLLib does not have functionality to re-serialize an xml object so there is no ability to modify or create XML. There are work arounds for this which I could detail in a later post if requested, but if you have complex XML it would be advised that you create your own dll that allows you to serialize and de-serialize XML.
This example also shows a really useful way to drive menus in Mapbasic from configuration. I have personally used similar code to this to drive menus based on a user privilege and context.
The example code can be downloaded here XML Example.zip
'Note the order of the includes
Include "MAPBASIC.DEF"
Include "XMLTypes.def"
Include "XMLLib.def"
Declare Sub Main
Declare Function LoadConfig() as Logical
Declare Sub ShowMenu
Declare Sub AdminUser
Declare Sub GeneralUser
Declare Sub AboutExample
Declare Sub ExitExample
Define CONFIG_FILE "XMLexample.config.xml"
Type MenuType
MenuName as String
MenuItemName() as String
MenuItemCallingSub() as String
End Type
Dim Mnu as MenuType
'-------------------------------------------------------------------
Sub Main
OnError Goto CatchExPrint Chr$(12)
'This could be called at any time from anywhere but in this example
'it initializes the menu at mbx start up
If LoadConfig() Then
Call ShowMenu
End If
Done:
Exit Sub
CatchEx: Note Error$()
Resume Done
End Sub
'-------------------------------------------------------------------
Function LoadConfig() as Logical
OnError Goto CatchEx
LoadConfig = false
'First check and see if xml file exists
If NOT FileExists(ApplicationDirectory$() & CONFIG_FILE) Then
Note "Configuration file " & CONFIG_FILE & " is not in the " & ApplicationName$() & " directory!"
Goto Done
End If
'Create an xml document
Dim xmlDoc as MIXmlDocumentxmlDoc = MIXmlDocumentCreate()
Dim parseErr, valid, resext as SmallInt
Dim i as SmallInt
Dim sXmlDocPath as String
sXmlDocPath = ApplicationDirectory$() & CONFIG_FILE
Print "Attempting to load - " & sXmlDocPath
'Load config into xmlDoc
i = MIXmlDocumentLoad(xmlDoc, sXmlDocPath, parseErr, valid, resext)
Print "parseErr " & parseErr
'Check load errors
If parseErr > 0 then
Note "Could not load " & ApplicationDirectory$() & CONFIG_FILE & Chr$(13) &
"This could be because the file contains invalid XML" & Chr$(13) &
"Please check " & CONFIG_FILE & " is valid and try again!"
Goto Done
End If
Print "Successfully Loaded - " & sXmlDocPath
'Select root node <Config>
Dim xmlRootNode as MIXmlNodexmlRootNode = MIXmlDocumentGetRootNode(xmlDoc)
Print "Loading Menu Settings....."
'XPath query to select menu config
Dim strXPath as String
strXPath = "/Config/Menus/Menu"
Dim xmlMenusList as MIXmlNodeList
xmlMenusList = MIXmlSelectNodes(xmlRootNode,strXPath)
'Select fist menu node
Dim xml_node as MIXmlNode
xml_node = MIXmlGetNextNode(xmlMenusList)
Dim strValue as String
strValue = String$(500," ")
Dim nLen As Integer
nLen = 500
'Get attribute value from Name attribute
i = MIXmlNodeGetAttributeValue(xml_node, "Name", strValue, nLen)Mnu.MenuName = strValue
Print "Menu Name - " & Mnu.MenuName
Dim xmlMenuItemsList as MIXmlNodeList
xmlMenuItemsList = MIXmlGetChildList(xml_node)
xml_node = MIXmlGetNextNode(xmlMenuItemsList)
Dim iMenuItemCount as Integer
iMenuItemCount = 1
Do While xml_node > 0
'Get element/node value for iMenuItemCount menu item
Redim Mnu.MenuItemName(iMenuItemCount)i = MIXmlNodeGetValue(xml_node, strValue, nLen)
Mnu.MenuItemName(iMenuItemCount) = strValue
'Get CallingSub attribute value for iMenuItemCount menu item
Redim Mnu.MenuItemCallingSub(iMenuItemCount) i = MIXmlNodeGetAttributeValue(xml_node, "CallingSub", strValue, nLen)
Mnu.MenuItemCallingSub(iMenuItemCount) = strValue
Print "Menu Item " & iMenuItemCount & " - " & Mnu.MenuItemName(iMenuItemCount) & " Calling " & Mnu.MenuItemCallingSub(iMenuItemCount)
'Get next note in the collection list
xml_node = MIXmlGetNextNode(xmlMenuItemsList)
iMenuItemCount = iMenuItemCount + 1
Loop
Print " "
LoadConfig = true
Done:
Exit Function
CatchEx:
Note Error$()
Resume Done
End Function
'-------------------------------------------------------------------
Sub ShowMenu
OnError Goto CatchEx
Dim strCommand as String
Dim i as Integer
'Here I build a command string with values from the xml configuration
strCommand = "Create Menu " & Chr$(34) & Mnu.MenuName & Chr$(34) & " As "
For i = 1 to Ubound(Mnu.MenuItemName())
If Mnu.MenuItemName(i) = "(-" Then
'Create menu spacer line
strCommand = strCommand & Chr$(34) & "(-" & Chr$(34)
Else
'Create Menu Item from configuration
strCommand = strCommand & Chr$(34) & Mnu.MenuItemName(i) & Chr$(34) & " Calling " & Mnu.MenuItemCallingSub(i)
End If
If i + 1 <= Ubound( Mnu.MenuItemName()) Then
'This just add the required comma unless it is the last item
strCommand = strCommand & ", "
End If
Next
Print strCommand ' for debug
Run Command strCommand
Alter Menu Bar Add Mnu.MenuName
Done:
Exit Sub
CatchEx:
Note Error$()
Resume Done
End Sub
'-------------------------------------------------------------------
Sub AdminUser
Note "Hello Admin Configured User"
End Sub
'-------------------------------------------------------------------
Sub GeneralUser
Note "Hello General Configured User"
End Sub
'-------------------------------------------------------------------
Sub AboutExample
Note "XML Example with Dynamic Menus"
End Sub
'-------------------------------------------------------------------
Sub ExitExample
End Program
End Sub
Here is the xml file that is used for configuration. If you want to remove a menu item eg: admin then just delete the menuitem line in the xml. Note: I did try to comment out using <!-- --> but the mapbasic xml implementation still read it?
<?xml version="1.0" encoding="utf-8"?>
<Config>
<Menus>
<Menu Name="XML Example">
<MenuItem CallingSub="AdminUser">Hello - Admin</MenuItem>
<MenuItem CallingSub="GeneralUser">Hello - General</MenuItem>
<MenuItem CallingSub="">(-</MenuItem>
<MenuItem CallingSub="AboutExample">About</MenuItem>
<MenuItem CallingSub="">(-</MenuItem>
<MenuItem CallingSub="ExitExample">Exit</MenuItem>
</Menu>
</Menus>
</Config>
Here is an example of the the dynamic menu used by Brendan Stone http://blog.nadnerb.co.uk/?p=125
ReplyDeleteThis is great little mbx for getting basemaps or background imagery
Cheers
Very good job . I was looking for this. Can you add some screenshots of result object please ?
ReplyDeleteHi Kurtarma, as posted above Brendan Stone posted a solution using this code, here http://blog.nadnerb.co.uk/?p=125
DeleteCheers
Good site. I'm trying to compile it, but i got an error: "Library GMLXlat.dll was not found. Unable to link to external library GMLXlat.dll."
ReplyDeleteYou can solve it easily, just download the file you need for example http://fix4dll.com/xinput1_3_dll and add it into your system 32 folder, try to it's very easy. Hope it will be useful for you. Good luck.
DeleteGreat job for publishing such a beneficial web site. Your web log isn’t only useful but it is additionally really creative too.
ReplyDeleteTwin Cities Web Design