MaXML 2.0 Released!

BlitzMax Forums/BlitzMax Programming/MaXML 2.0 Released!

John J.(Posted 2006) [#1]
(XML is a widely used and accepted format applied anywhere from word-processors to level builders)

MaXML makes it easy to load, manipulate, and save XML files. MaXML is a very easy to use library of functions for manipulating xml data, including an extremely fast xml parser, which is 16 - 736 times faster than it's competitor:

With a 1.3 MB XML file (on a Pentium 4 3.0 Ghz HT):
MaXML 2 parses in: ~290 Milliseconds
Competitor parses in: ~214840 Milliseconds

With a 50 KB XML file (on a Pentium 4 3.0 Ghz HT):
BlitzXML 2 parses in: ~10 Milliseconds
Competitor parses in: ~160 Milliseconds

New features in MaXML 2.17:
* The new xmlNode.FindChildEx() method (by Jake L.) now allows you to find nodes with specific attributes.
* The new xmlNode.SortChildrenEx() is much more flexible, allowing nodes to be sorted in almost any way you want.


New features in MaXML 2.1:
* XML files can now be loaded and saved in binary format seamlessly! (Binary files load/save about 1.5 times faster than standard XML format)
* The ability to sort nodes alphabetically based on node name, node value, attribute name, or attribute value.


New features in MaXML 2.0:
* A extremely fast, highly optimized XML parser, capable of parsing well over 4.5 MB per second (although this may vary depending on your computer's speed)
* Many new features, including node.MoveTo(), node.CopyTo(), node.Copy(), node.SortChildren(), node.SwapWith(), node.SetIndex() (for custom node ordering), etc., etc., etc.


Click here for a BlitzBasic version of MaXML



Download MaXML 2.22 Module (ZIP) - 230 KB

Included with MaXML_v2.22.zip is documentation, example code, and a Getting Started guide.

To install, simply drag the "maxml.mod" folder in the MaXML archive to your the mod/pub.mod folder under your BlitzMax install.

License: MaXML is completely free for commercial and personal use.


Haramanai(Posted 2006) [#2]
I am using MAXML to much right now and I felt the need to say :
Thanks
and :
Please make this thread stick.


Haramanai(Posted 2006) [#3]
I have and one request :
A method in the xmlDocument that will return the number of the nodes.


John J.(Posted 2006) [#4]
Ok. I'll try to add that in that next update.


Dreamora(Posted 2006) [#5]
Very usefull module.
Never really overcame my fear of using or parsing in XML till now.

Thank you :-)


Beaker(Posted 2006) [#6]
Have you considered adding XML sockets? Might be quite complicated to code but accessing and manipulating remote XML files is a great feature.


VP(Posted 2006) [#7]
Great module, takes the sting out of XML.

A word of caution to those wanting to implement XML for all their config storage or database-ish stuff: XML is hardly very lean-and-mean when it comes to storing data. Flexibility is its forte, not efficiency.

I've seen too many game config files (and in-game object descriptors) stored as external XML where an INI file style of storage would have been just as useful and half the size.

I'm all for XML being used in applications where it proves its worth (EDI being a notable perfect application), but lets keep the complexity down where possible, eh chaps? ;)


Dreamora(Posted 2006) [#8]
I only use it for stuff that has a hierarchy component, where the node based structure has a use.
I think too, for config files its a quite bad overhead which only makes it harder to config the file manually (which some freaky user still tend to do like me ;-))


John J.(Posted 2006) [#9]
vinylpusher: It's true that XML is not completely as efficient as INI or a few other formats, but I think it's flexibility and structure easily makes up for it's filesize. For example, if my .8 KB tank files in my tank game were .5 KB with INI, it really makes no difference at all for loading (both 0 millisecs - in fact, most INI parsers may even be slower than MaXML), and these days I hardly think a few extra KB's will make much of a difference. However, I definitely agree that a binary file format should usually be used if you are loading extremely large amounts of "raw" data (such as an image file, or the positions of 50,000 trees). For almost all purposes, XML is ideal (for me, at least :), but if XML just doesn't work well for your purposes, there's no point in using it, and that's fine with me.

Beaker: I haven't really considered adding XML sockets until now, but I'll see what I can do :)


VP(Posted 2006) [#10]
John J.: Don't get me wrong, I know that the processing overhead (thanks to your work!) is not an issue. I just want people to think before they implement :)

I know I will be using XML in an upcoming project and it is your mod I will be doing it with.

Filesize can be an issue in some cases, though you are right in saying it is not as important these days. I'm looking to the future (10-25 years down the line). Bandwidth charges will be steadily increasing and people will again begin considering every last byte!

I think there's a proposal for a binary format for storing XML. I don't know if it is close to being a standard but for the time being I think zlib compression would be a good additional option for any xml files over 2k in size.


John J.(Posted 2006) [#11]
I just want people to think before they implement :)

Definitely! I'm not saying that your point is wrong; I agree with you that saving file space is important. I just can't see the world going back to the days where you would say "WOW!!! 16KB RAM???"

I've been planning to impliment a binary alternate into MaXML where you can load/save a binary version of your XML files which is streamlines for speed and filesize.


Difference(Posted 2006) [#12]
If size is your concern, XML files zip very well. Openoffice, opendocument etc. simly zip the xml file(s) to one package.

BlitzMax allready has the zlib , so it sould be pretty straight forward to go that way.


N(Posted 2006) [#13]
I have to agree with JohnJ here. Being concerned about a ~2kb Xml file is really just insane now.

As for Xml itself, it's nice, but it's kindof overkill for what I do, so I invented my little SParse module. Cower.Xml is a heap o' crap now (as evidenced by JohnJ's work here). I might rewrite it, but I doubt it. Probably just use JohnJ's module instead -- beats reinventing the wheel, so to speak.


John J.(Posted 2006) [#14]
Update:
* Fixed bug where xmlNode.FirstChild() and xmlNode.LastChild() would crash when no node children exist
* Added ability to sort nodes based on node name, node value, attribute names, and attribute values
* Added binary XML file support for faster loading + saving

vinylpusher: Strangely, the binary format seems to be almost exactly the same size as a standard XML file. I'll probably add compression next.


VP(Posted 2006) [#15]
It might depend on the size of the XML file. I know zlib compression's break-even point is roughly 2K for a text file, perhaps a similar issue with the binary XML format?

Some XML files can get pretty large, like Word documents. I'm mulling the idea of a sales/invoicing/inventory system which outputs Word compatible XML when you want to generate an invoice or delivery note. The generated XML files need to be fed into a database, so I am concerned about size. A simple, single-page Word XML file is 23KB. Multi-page invoices with 100's of line items is probably going to push half a meg. Multiply that by a few hundred thousand over the lifetime of the system and you start to fill hard drives (and slow the database down).

Zlib would work wonders :)


Jay Kyburz(Posted 2006) [#16]
Hey John, I was just installing this on my pc and knoticed there is no entry for maxml in the code archives section of the website.


Booticus(Posted 2006) [#17]
John thanks again for the module. Its very neat!


morszeck(Posted 2006) [#18]
It's a cool Tool !!! This simplify me some. Because it's very fast also.

Something can add in addition:

mynode.SetAttribute( "name", "value" )

Because,

mynode.Attribute( "name" )

if "name" is not available, so automatically a "name".


John J.(Posted 2006) [#19]
Hey John, I was just installing this on my pc and knoticed there is no entry for maxml in the code archives section of the website.

I didn't put it in the code archives because I would be declaring it public domain. If I submitted it to the code archives under public domain, would I still own the copyright to MaXML?



morszeck: I'm not quite sure I understand. Is there a feature you want me to add? To add an attribute, just do this:
mynode.Attribute("name").Value = "value"

And to read an attribute, you can do this:
value$ = mynode.Attribute("name").Value

And if you want to detect when an attribute does not exist, you can do this:
If mynode.HasAttribute("name") = False Then Throw "Cannot find ~qname~q attribute!"



morszeck(Posted 2006) [#20]
When the root is:
<test>

now, i write:

root = mydoc.Root()
root.Attribute("name")

then becomes automatically:

<test name="">

Is this so meant?


John J.(Posted 2006) [#21]
Yes, that's the way it's supposed to work. Attribute() is meant as an easy way to read or write node attributes. However, the statement "root.Attribute("name")" on it's own is no use, really, unless you do something like "root.Attribute("name").Value = ...".

If you still end up with alot of "blank" attributes like that, you can always call node.CleanAttributes(), which removes them for you.


morszeck(Posted 2006) [#22]
Ok, thx... but the error messages must be still improved. Get time to time errors from Linker. Without line number or so ...


John J.(Posted 2006) [#23]
Get time to time errors from Linker.

That's strange. Could you list some of the errors you're getting?


morszeck(Posted 2006) [#24]
This is the error message:

Building xmldoc_creater
Compiling:xmldoc_creater.bmx
flat assembler version 1.64
3 passes, 21325 bytes.
Linking:xmldoc_creater.debug.exe
C:/Programme/BlitzMax/bin/ld.exe: cannot find C:/Programme/BlitzMax/mod/_n = root_n.mod/addnode(
Build Error: Failed to link C:/Dokumente und Einstellungen/rene/Desktop/BlitzMax_Editor_2/xmldoc_creater.debug.exe
Process complete


// Edit //

It's a Bmax Bug. See here: http://www.blitzbasic.com/Community/posts.php?topic=57112

A variable name "import_n" in a Method create an linker error!!!


John J.(Posted 2006) [#25]
That's weird - "import_n" causes a linker error for me too (but I'm not using the latest BlitzMax version, so I don't know if it's fixed already or not). MaXML doesn't use any variables called "import_n", so at least MaXML is safe for now.


John J.(Posted 2006) [#26]
Update: Version 2.15 includes some misc. bug fixes (escape codes were not being loaded/saved properly).


MadMunky(Posted 2006) [#27]
Is there a version out for Blitzmax 1.18 yet or any way of getting it working?

Why is it every bmax update u have to redownload all mods its a pain!


John J.(Posted 2006) [#28]
I'll upload a re-compile after downloading BlitzMax 1.18, which should hopefully fix this.

P.S. Until then, you could re-compile it yourself. Just type "bmk makemods pub.maxml" at a command prompt.


FlameDuck(Posted 2006) [#29]
Couldn't you talk to skidracer about getting this added to the axe repository?


MadMunky(Posted 2006) [#30]
i tryed to re-compile it but still doesnt work :(


drnmr(Posted 2006) [#31]
mine says "can't find interface for module 'pub.maxml'"
i'm using bmax 1.18.


AntonyWells(Posted 2006) [#32]
You can strip the module lines and just import it into your project manually. just copy the source from the mod folder to your project and type 'import "MaXml.bb"


John J.(Posted 2006) [#33]
I'm trying to update MaXML, but I'm having trouble downloading BlitzMax 1.18 (the download keeps terminating early causing a corrupted exe) - probably because of my slow dial-up connection.

I'll keep trying.


drnmr(Posted 2006) [#34]
aurora- ???


John J.(Posted 2006) [#35]
Aurora means that you can import it as a source file, instead of a module (if you remove or comment out the Module and ModuleInfo lines)

Anyway, I finially got the latest BMax version, so hopefully I'll have a working version up soon.


John J.(Posted 2006) [#36]
Update: The latest version of MaXML is now compatible with BlitzMax 1.18.


Tachyon(Posted 2006) [#37]
I would really enjoy seeing some more examples (sample code) of this XML module in action. Does anyone feel generous enough to a few bits of code, pretty please?? :) Thanks!


Sean Doherty(Posted 2006) [#38]
John,

I'm trying MaXML, but if I load my file over and over I eventually get an error or odd results. Is there any bugs I should be aware of? Here is my module:



Works must of the time?


Sean Doherty(Posted 2006) [#39]
XML File:

<?xml version="1.0"?>
<StarchonMap>
   <Header>
      <Title>Foot Hold</Title>
      <Author>Sean Doherty</Author>
      <Description>The Bio Race has attached a Common Wealth Member and established a Base of operations.</Description>
   </Header>
   <Sector>
      <OID>10</OID>
      <Name>Toga Prime</Name>
      <X>800</X>
      <Y>300</Y>
	<Starship>
	   <X>0</X>
	   <Y>0</Y>
	   <HullOID>2</HullOID>
	   <PlayerOID>2</PlayerOID>
	</Starship>
	<Starship>
	   <X>0</X>
	   <Y>0</Y>
	   <HullOID>2</HullOID>
	   <PlayerOID>1</PlayerOID>
	</Starship>
	<Starship>
	   <X>0</X>
	   <Y>0</Y>
	   <HullOID>2</HullOID>
	   <PlayerOID>1</PlayerOID>
	</Starship>
   </Sector>
   <Sector>
      <OID>11</OID>
      <Name>Earth</Name>
      <X>800</X>
      <Y>500</Y>
	<Starship>
	   <X>0</X>
	   <Y>0</Y>
	   <HullOID>2</HullOID>
	   <PlayerOID>2</PlayerOID>
	</Starship>
   </Sector>
</StarchonMap>



Sean Doherty(Posted 2006) [#40]
John,

I put some test code in place and it seems that on a fairly regular basis the following lines return a null node when they should not:

pStarshipXmlNode = pSectorXmlNode.FindChild("Starship")

and

pSectorXmlNode = pSectorXmlNode.NextSibling()

Any idea what I'm doing wrong?


John J.(Posted 2006) [#41]
Your code seems to work fine for me. I stepped through the entire load process and it seemed to process every node properly. I also ran it several times in the same program, and the output was the same:

Reading XML SectorOID = 10
Loading Starship
Starship
Loading Starship
Starship
Loading Starship
Reading XML SectorOID = 11
Loading Starship

If what you are describing is a MaXML bug, I will try to fix it as soon as possible, but until I can reproduce the problem, I doubt I will get very far.


Jake L.(Posted 2006) [#42]
Hi John,

I "wrote" a function FindChildEx, which not only looks for a given node-name but for a matching attribute as well. Example: mydata:xmlnode=FindChildEx ("playerdata","name","Jake")

Maybe you want to add this to your official mod.

Here's the code:


I have a hard time to modify your SortNode code to just sort children of a given nodename. This could be useful as well (I have a node <typedef> with children-nodes <field> and <function> and would like to sort the fields as well as the functions). Any idea?

Anyway, you should know that I dropped any .ini/registry-stuff since using your lib - it's easy to use and works like a charm.


John J.(Posted 2006) [#43]
Thanks for the code for FindChildEx() - it looks useful. I'll include it with the official version of MaXML soon.

I have a hard time to modify your SortNode code to just sort children of a given nodename.

I probably need to re-write that sort code - it's a little messy. Anyway, I'll see what I can do to add that feature to MaXML. Do you just want the ability to sort nodes of a specific name?


Jake L.(Posted 2006) [#44]
In detail, sorting childs (of just a given name) by an attribute or value.

Example (using a node's value here, but could be attribute as well):

<typedef>
<function>ASome</function>
<function>CSome</function>
<global>CDSome</global>
<function>BSome</function>
<global>ASome</global>
<global>BSome</global>
</typedef>

Now, the end result should look like:

<typedef>
<global>ASome</global>
<global>BSome</global>
<global>CDSome</global>
<function>ASome</function>
<function>BSome</function>
<function>CSome</function>
</typedef>

To do this, I first need to sort by nodename (SortChildren can do this atm) and then each "subset" (<global> and <function>) by it's value. Maybe you could enhance SortChildren to sort by attribute/value just a given subset (=nodename).


John J.(Posted 2006) [#45]
How about adding the ability to do this:
Node.SortChildren(SORTBY_NODE_NAME + SORTBY_NODE_VALUE)

(sort of like Blitz3D's entity flags)
This way, you could sort nodes any way you want very easily.


Jake L.(Posted 2006) [#46]
Sounds very good! Can't wait for the next version ;)


John J.(Posted 2006) [#47]
New features in MaXML 2.17:
* The new xmlNode.FindChildEx() method (by Jake L.) now allows you to find nodes with specific attributes.
* The new xmlNode.SortChildrenEx() is much more flexible, allowing nodes to be sorted in almost any way you want.



Sean Doherty(Posted 2006) [#48]
John,

Did you find the issue I reported?

Thanks


John J.(Posted 2006) [#49]
So far I haven't been able to reproduce the issue. If you could send me some example code (along with an xml file, if possible) which demonstrates the problem, I would be able to fix it much quicker.


JonasL(Posted 2006) [#50]
MaXML is a really nice module. Thanks for providing it. I have downloaded the version 2.17.

On MacOS X I had to "Build Modules" to make it work and after that it works just fine.

On my WinXP machine, however, I get an "Unhandled Exception: Illegal bank offset", when running both example programs. I guess there is some problem with the build and the latest version of BlitzMax.

I just wanted to report it. I'm no BMX wizard, but I guess the problem can be solved by building the modules. However, in Win the menu items are disabled, so I guess I need to install something first. Guess I need to hit the documentation and the forums to find out. ;)


John J.(Posted 2006) [#51]
JonasL: Until I release a re-compiled version, you can re-make the module yourself by going to MS-DOS command prompt and entering the following:

"cd C:\Program Files\BlitzMax\Bin"
"bmk makemods pub.maxml"
"docmods"

... then everything should be up to date.


JonasL(Posted 2006) [#52]
John J: Thanks. It now works like a charm in Win as well. Great work with this module. Now I can continue working with our new game Stray Hero (sorry, no info on the web site yet). I really wanted XML support for data files to make them more editable.


John J.(Posted 2006) [#53]
Update: MaXML 2.18 fixes a bug where Unix-style return characters in a file causes an error (also, MaXML 2.18 is recompiled with the latest version of BlitzMax).


Gabriel(Posted 2006) [#54]
I'm getting problems with this in Release mode. I have a loop which loops through all the nodes which are children of the root node.

   Local node:xmlNode=root.FirstChild()
   While node <> Null
      If node.Name = "ImagePackImage" Then
         ' DO STUFF
      Else
         Debug_Log "INVALID NODE TYPE"+node.Name
      End If
      node = node.NextSibling()
      If node=Null
         Debug_Log "FOUND LAST NODE"
      End If
   Wend


In debug mode, it works fine and finds every node. In release mode, it stops finding nodes long before it finds the last one. It does not error in my code ( verified because "FOUND LAST NODE" is written to my custom debuglog ( since there is no Blitz debuglog in Release mode )

Any idea why NextSibling might start returning a null node in release mode and not in debug? I've checked the XML file and it's great. It was also created with your module.


EDIT: I'm debugging your module as best I can, and will post more info as I find it.

Specifically, NextSibling is returning Null because it believes the node I pass to it does not have a parent, which of course it must or it would never have been returned as a sibling the time before :/

EDIT2: I've tried rewriting my code to use ChildCount() and GetChild() but that works perfectly in debug mode and just MAV's in Release mode. Presumably for a similar or the same reason.


Gabriel(Posted 2006) [#55]
Just to confirm, it's definitely a problem with MaXML because I've just changed my modules and code to use LibXML instead and the problems vanish with LibXML.


John J.(Posted 2006) [#56]
Thanks for letting me know about this. I'll try to fix it ASAP.


John J.(Posted 2006) [#57]
Unfortunately, I'm still having trouble finding the cause of the debug/release problem. I'm beginning to think it's a problem with Blitzmax, since it works perfectly in debug mode, and everything operates as I would expect it to, but in release it crashed for no apparent reason. At least, I'm reasonably certain that no compiler should ever have major behavioral differences between debug and release like this.

Just to confirm, it's definitely a problem with MaXML because I've just changed my modules and code to use LibXML instead and the problems vanish with LibXML.

Maybe the problems vanish with libxml because libxml was written in C, not BlitzMax (the libxml module for BlitzMax is simply a wrapper, which allows access to the C code through BlitzMax). Unfortunately, I may eventually be forced to port MaXML to C++ (since I have never encountered major debug/release inconsistancies with C/C++). Then, I would make a wrapper in BlitzMax so you could use it in BlitzMax. Hopefully, I won't have to resort to this, however.


Gabriel(Posted 2006) [#58]
Yes sorry, when I said it's definitely a problem with MaXML, I meant as opposed to my use of it, not as opposed to BlitzMax itself. I did have a good look through your code and I couldn't find anything either, so you may well be right that it's a BlitzMax issue or bug.

As you say, the only differences between debug and release should be bounds checking and things like that. There shouldn't be any behavioural differences, so it's indeed very odd.


skidracer(Posted 2006) [#59]
How do I go about reproducing this bug?


Gabriel(Posted 2006) [#60]
I've since rewritten all my code to use LibXML, so I don't have the example handy any more. I've got a lot on today, but I'll try to cobble together a quick sample and include the XML file to go with it. Hopefully tomorrow. I really have no idea whether or not the problem lies with BlitzMax or MaXML though.


John J.(Posted 2006) [#61]
skidracer:
Here is how to reproduce the problem I encountered when trying to run one of the MaXML examples in release mode:


Software:
BlitzMax Version: 1.20 (latest)
MaXML Version: 2.18 (latest)


Test code:
Import pub.MaXML

Strict

Local node:xmlNode, root:xmlNode
Local name:String
Local foundSomething = False

Local XMLFile:xmlDocument = xmlDocument.Create("example2.xml")	
root = XMLFile.Root()

root.SortChildren(SORTBY_ATTR_VALUE)


Example2.xml contents:
<?xml version="1.0"?>
<addressbook title="XML Address Book Example">
  <person firstname="Bob" lastname="Johnson">
    <phone>456-6784</phone>
  </person>
  <person firstname="Joe" lastname="Roberts">
    <phone>155-8776</phone>
  </person>
  <person firstname="Bill" lastname="Baker">
    <phone>955-3744</phone>
  </person>
  <person firstname="Robert" lastname="Jones">
    <phone>153-4487</phone>
  </person>
  <person firstname="Phillip" lastname="Taginski">
    <phone>205-0986</phone>
  </person>
  <person firstname="George" lastname="Smith">
    <phone>577-2264</phone>
  </person>
    <phone>754-2908</phone>
  <person firstname="Luke" lastname="Jackson">
    <phone>123-4567</phone>
  </person>
  <person firstname="Guy" lastname="Wilson">
    <phone>131-1313</phone>
  </person>
  <person firstname="Alan" lastname="Drake">
    <phone>332-9179</phone>
  </person>
</addressbook>



Debug mode output:

Building test
Compiling:test.bmx
flat assembler version 1.64
3 passes, 2756 bytes.
Linking:test.debug.exe
Executing:test.debug.exe

Process complete




Release mode output:

Building test
Compiling:test.bmx
flat assembler version 1.64
3 passes, 1599 bytes.
Linking:test.exe
Executing:test.exe
Unhandled Memory Exception Error
Process complete




skidracer(Posted 2006) [#62]
Yikes,

The problem with that code is XMLFile has been garbage collected. Adding a reference to the end of the problem code stops the crash:
Import "MaXML.bmx"

Strict

Local node:xmlNode, root:xmlNode
Local name:String
Local foundSomething = False

Local XMLFile:xmlDocument = xmlDocument.Create("example2.xml")	
root = XMLFile.Root()


root.SortChildren(SORTBY_ATTR_VALUE)

root = XMLFile.Root()


So what is happening?

When a List goes out of scope the _head link must be cleared (nulled), so the your node.sort method I think is crashing due to the unexpected destruction of the document from under it and hence the unexpected nulling of the _head member. Short of making _head private we're bashing our heads on a rational fix for this.

The reason the above only crashes in Release mode is that unfortunately garbage collection is a lot more aggressive in release where temporary objects may be held for shorter times in registers instead of the stack and hence they can get collected earlier.

For a temporaty fix for MaXML you could add to xmlNode:

Field _Owner:xmlDocument

and in the RootNode creation add:

_RootNode._Owner=Self

Getting rid of the _RootNode and having xmlDocument extend xmlNode also seems to work well and doesn't create the problematic circular dependency that the above does.


John J.(Posted 2006) [#63]
skidracer: You're right - adding a pointer to the xmlDocument seems to fix it. But there's something I don't understand - how is the garbage collector deleting something before the program is done with it? Isn't it supposed to check if there are any references to an object before deleting it? (and therefore removing the possibility of the garbace collector deleting an object before the program is done with it like what has happened here)?

Update: Version 2.19 will hopefully fix any problems related to debug/release inconsistancies.


skidracer(Posted 2006) [#64]
The list is being collected because the only thing left in use are the links, the list destructor needs to break the circular reference nature of the link set so the problem is the behavior of the list destructor which shouldn't affect you but it needs to force _head._value to null in order it break another circular reference which is what is causing the problem.


Mark Tiffany(Posted 2006) [#65]
Short of making _head private we're bashing our heads on a rational fix for this.

So the proper fix would be to have Private work inside Types?

Please? Can we please see Private fields / methods / functions in Types sometime soon? Pretty please? I've got some cherries handy...?


John J.(Posted 2006) [#66]
Update: MaXML 2.20 fixes a bug where manual ASCII escape codes (like "&#13;") were not being parsed correctly.

You can get the latest version here.


dooz(Posted 2007) [#67]
There is a bug in the xmlDocument.Create() method (or in BlitzMax, but I can't reproduce it). When I call it without an argument such as in:

Strict
Import pub.maxml
Local xml:xmlDocument = xmlDocument.create()
End

I get:

Building test3
Compiling:test3.bmx
flat assembler version 1.66
3 passes, 2283 bytes.
Linking:test3.debug.exe
C:/Documents and Settings/Paul/My Documents/Devel/blitzmax/maxml/.bmx/test3.bmx.gui.debug.win32.x86.o(code+0xc6): undefined reference to `_1'
Build Error: Failed to link C:/Documents and Settings/Paul/My Documents/Devel/blitzmax/maxml/test3.debug.exe
Process complete

The function is:

Function Create:xmlDocument(Url:Object = "")
Local doc:xmlDocument = New xmlDocument
If Url <> "" Then doc.Load(Url)
Return doc
End Function

By the way, you should probably have written not in terms of strings. Instead, using:

Function Create:xmlDocument(Url:Object = null)
Local doc:xmlDocument = New xmlDocument
If Url Then doc.Load(Url)
Return doc
End Function


Brucey(Posted 2007) [#68]
Try a non-Quick build of the app.

Sometimes, if you've changed a module, a quick build can still be trying to link to module code that no longer exists...


..just a thought.


dooz(Posted 2007) [#69]
I never use quick build, have had problems with it in the past. So it's not that.

Thanks anyway


pappavis(Posted 2007) [#70]
What are the chances of implementing some Xpath query possibilities?

I was thinking about a method like:
* SelectSingleNode(strXpathQuery) --> Returns a xmlNode

Both MaXML and the Dotnet Compact Framework 1.1 both doesnt have Xpath (I may be mistaken). I'd prefer to use a quick 'n simple XPath query to retrieve a node or attribute value, instead of using a iterated loop.

This is the XML for which i'd like to use;

<?xml version="1.0" encoding="utf-8"?>
<objects>
	<object id="1" type="type1" image="gfx/plaatje1.jpg" animframes="0"/>
	<object id="2" type="type2" image="gfx/plaatje2.jpg" animframes="0"/>
</objects>
<levels>
	<level level="1">
		<player itemnumber="1" initiateEnemyWhenPlayerY="120">
			<enemy uniqueID="1" type="type1">
				<movements id="1" startX="230" startY="291" destinationX="540" destinationY="475"/>
				<movements id="2" startX="540" startY="475" destinationX="610" destinationY="231"/>
				<movements id="3" startX="610" startY="231" destinationX="-120" destinationY="-200"/>
			</enemy>
			<enemy uniqueID="1" type="type2">
				<movements id="1" startX="610" startY="231" destinationX="-120" destinationY="-200"/>
			</enemy>
		</player>
		<player itemnumber="2" initiateEnemyWhenPlayerY="230">
			<enemy uniqueID="1" type="type2">
				<movements id="1" startX="230" startY="291" destinationX="540" destinationY="475"/>
				<movements id="2" startX="540" startY="475" destinationX="610" destinationY="231"/>
			</enemy>
		</player>
	</level>
</levels>



Overall, thanx for a great job :)


SebHoll(Posted 2007) [#71]
Hi John,

Brilliant module - it makes it quick and easy to save/load xml files. One problem though - if a file string is passed to the Load() method of an xmlDocument, and the file isn't an actual XML file, the entire program crashes out.

Would it be possible to gracefully return a value of False from the Load() method if an xmlDocument suspected to be FORMAT_XML is only a standard non-XML text file, instead of it trying to be unsucessfully parsed? At the moment, if a user accidentally opens a regular text file by mistake, I can't catch the error and the whole program terminates. :(


Cheers


Seb


John J.(Posted 2007) [#72]
Update: MaXML 2.21 fixes a bug where some parse errors are not handled correctly (crashing the application).

You can get the latest version here.


Seb: Thanks for letting me know about that, it's fixed now. Now all XML parse errors should be thrown properly, so you can catch them and respond to the situation appropriately.

pappavis: I'm not sure what an Xpatch query is, but from your description, it sounds like FindChild() / FindChildEx() / FindSibling() would work (though I'm probably wrong). I probably won't be adding many new features to MaXML any time soon (though I'll always try to provide quality support :) ), but maybe Brucey's libxml has the features you need.


SebHoll(Posted 2007) [#73]
Cheers John - brilliant job! Works perfectly and I can easily handle the errors using Try/Catch.


Brucey(Posted 2007) [#74]
John, an XPath looks like a directory path that points to a certain node in a tree.
<levels>
	<level level="1">
		<player itemnumber="1" initiateEnemyWhenPlayerY="120">
			<enemy uniqueID="1" type="type1">
			</enemy>
		</player>
	</level>
</levels>

The XPath to enemy might look something like : levels/level/player/enemy
(which actually refers to *all* enemy nodes for player)

But it's a lot more flexible, since you can also access paths based on ranges of attribute values and such like.

:-)


John J.(Posted 2007) [#75]
Update: Fixed a bug where &#xxx; codes were not being processed inside of quotes, and &amp; codes were not being processed at all.

You can get the latest version here.


jsp(Posted 2007) [#76]
Thanks for update, did just some tests and works fine now with my xml attributes.


Filax(Posted 2007) [#77]
Many thanks for this great piece of code :)


Vertex(Posted 2007) [#78]
Dear John J.,

I use MaXML currently but here thinks that would be nice:
- No Pub Module Scope. Please use an own like JohnJ.MaXML
- Set it into SuperStrict mode. There are only the constants and some integer values to bring it into XYZ:Int form
- There is no need to import BRL.Retro
- A node without childs is saved like "<pause length="2"/>" it where nice when it saved to "<pause length="2" />"
- Node levels have actual 2 white spaces, 1 white space would be nice:
<song>
  <info>
    <interpret>Smash Mouth</interpret>
    <title>All Star</title>
  </info>
</song>
should be:
<song>
 <info>
  <interpret>Smash Mouth</interpret>
  <title>All Star</title>
 </info>
</song>

You can eventually define a method for userdefined whitespaces like tabulators, 3 white spaces or so on.
(But can you tell me now, how to edit _WriteNode to use 1 white space and solve this "/>"-problem?)

What is with encoding? Is that utf-8?

Thank you for this module!

cu olli


Derron(Posted 2007) [#79]
If you searched for "/>" within the module's source:

Function _WriteNode(File:TStream, Node:xmlNode)


...
	If Node.HasChildren() = False Then
		If Node.Value = "" Then
			File.WriteLine Indent + "<" + NodeContents + "/>" 
		Else
		    File.WriteLine Indent + "<" + NodeContents + ">" + _AddEscapeCodes(Node.Value) + "</" + Node.Name + ">"
		End If
...


I think you'll find the correct spot ;D


The module relies on strictly used utf-8... if your encoding has some mistakes in it, it will throw an exception (as long as my brain reminds me correctly).

bye
MB


Vertex(Posted 2007) [#80]
Yes, I have edited the wrong file... So there where no changes in the output xml files.

Also I have edited WriteNode_ to:
	...
	Indent = Indent[ .. Node.Level]
	Indent2 = Indent2[ .. (Node.Level+1)]
	...


Now it works, thank you!

I will test the encoding with german umlauts Ä, Ü, Ö or the german s-z-ligation ß

cu olli


thalamus(Posted 2007) [#81]
I'm *really* keen to use this but the program seems to throw up an error when it encounters lines such as:

<!DOCTYPE DatabaseInventory SYSTEM "DatabaseInventory.dtd">


Removing this from the files isn't really an option - any chance of a fix? :)


Leon Drake(Posted 2007) [#82]
hmm whenever i use this command

Import pub.maxml

Local indexdoc:xmlDocument = xmlDocument.Create()


I get
Linking:eoled.exe
C:/Program Files/BlitzMax/endsoflegend/.bmx/eoled.bmx.gui.release.win32.x86.o: undefined reference to `_1'
Build Error: Failed to link C:/Program Files/BlitzMax/endsoflegend/eoled.exe


jsp(Posted 2007) [#83]
You could use New instead of Create

Import pub.maxml

Local indexdoc:xmlDocument = New xmlDocument