Libxml question

BlitzMax Forums/BlitzMax Programming/Libxml question

SpaceAce(Posted 2006) [#1]
I've been studying the documentation and examples included with libxml but for the life of me, I can't figure out how to create a document from scratch. All of the examples seem to hinge on parsing an existing document. What do I do if I want to create a complete XML document out of thin air?

The main problem seems to be that when I create a new document using newDoc, I can't get a pointer to an existing node (such as with getRootElement()) because none exist. Without a pointer to the current node, I can't add new nodes.

SpaceAce


Brucey(Posted 2006) [#2]
I agree, the documentation could do with having a few more examples... will have a look at adding more.

But for now, how's about this little one :
' create a new XML document, and populate it with some stuff

SuperStrict

Framework BaH.Libxml

' Create a new document
Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")

' Create a new node, initially not attached to any document
Local rootNode:TxmlNode = TxmlNode.newNode("myrootnode")

' Make the node our document root node
doc.setRootElement(rootNode)

' Add a child node to the root node
Local child:TxmlNode = rootNode.addChild("achild", Null, "Text for the child!")

' Add an attribute to the child node
child.addAttribute("name", "bob")

' Output the document to stdout
doc.saveFormatFile("-", True)

which should output the following :
<?xml version="1.0"?>
<myrootnode>
  <achild name="bob">Text for the child!</achild>
</myrootnode>


For making browsing the documentation a bit easier, you might want to look at my recent docmods tweak which adds method and function summaries for each Module and its types. Helps me find things much more quickly - rather than having to scroll through hoping something jumps out at you. (or there's that hotdocs thing, which may be to your taste).

The main problem with examples is the sheer amount of API there would be to make examples for...

:-)


SpaceAce(Posted 2006) [#3]
Hi, Brucey. Thanks for the reply. Is the example you posted already part of the documentation? If so, I don't know how I missed it but it does help to clear things up. Thanks for posting it here. I'll check out your docmods tweak, too.

SpaceAce


Brucey(Posted 2006) [#4]
I'm afraid it was only written in reply to your post, but I'll be adding it for the next update.


SpaceAce(Posted 2006) [#5]
Hm... I encountered something else odd, so I figured I'd resurrect this thread.

In my code, I create a new document with this basic structure:

<AllScores>
  <GlobalScores>
    ...
  </GlobalScores>
  <LevelScores>
    ...
  </LevelScores>
</AllScores>


The document saves fine when I create it from scratch. However, when I load it into an XmlDoc using parseFile and then add children like this...

  ' Levelnode is set to <LevelScores> earlier in the code
  Local Node:TxmlNode = LevelNode.addChild("Level"+LevelNum)
  Node.addAttribute("name", LevelScoreString[0])
  Node.addAttribute("score", LevelScoreString[1])


... the formatitng gets mangled, and all the new children get put on one line, followed by the </LevelScores> tag.

<child1 name="whatever" score="whatever" /><child2 name="whatever" score="whatever" /><child3 name="whatever" score="whatever" /><child4 name="whatever" score="whatever" /> </LevelScores>


This only happens when I use parseFile() to load an existing document. When I create the document from scratch, all the elements seem to be formatted and positioned correctly.

SpaceAce


Brucey(Posted 2006) [#6]
Hi Ace,

I see what you mean... so I had a rummage through the Libxml mailing list archives and found a post by the Libxml author who recommends that the "new" reader api is used to load files as it gives you more control of how it is handled via "options" params.

So, in good ole Blue Peter fashion... here's one I prepared earlier (or rather, moments ago)...
SuperStrict

Framework BaH.Libxml

' Create and save a document...

Local doc:TxmlDoc = TxmlDoc.newDoc("1.0")

Local rootNode:TxmlNode = TxmlNode.newNode("AllScores")

doc.setRootElement(rootNode)

rootNode.addChild("GlobalScores", Null, Null)
rootNode.addChild("LevelScores", Null, Null)

doc.saveFormatFile("indent_test.xml", True)

doc.free()
doc = Null


' Load the doc using the Reader API...

Local reader:TxmlTextReader = TxmlTextReader.fromFile("indent_test.xml", Null, XML_PARSE_NOBLANKS)
reader.read()

doc = reader.currentDoc()

' free up reader
reader.free()
reader = Null

' add some stuff
Local Node:TxmlNode = TxmlNode(doc.getRootElement().getFirstChild()).addChild("Level1")
Node.addAttribute("name", "brucey")
Node.addAttribute("score", "2")

' show doc
doc.saveFormatFile("-", True)

The key here is in the option passed into the TxmlTextReader fromFile() function : XML_PARSE_NOBLANKS

The issue arises because those indents you see in the saved xml are interpreted by Libxml on loading as "Text Nodes" (as they should be), and by default Libxml leaves *all* text nodes alone (well, you might want a node that has only spaces preserved for some reason!), and hence after you modify the xml, it can't then re-arrange the nodes to be indented - because of those text nodes.
The option XML_PARSE_NOBLANKS causes Libxml to strip out "empty/blank" text nodes so that when it comes to saving it with formatting, it can do so (by adding those nice spaces).
As the author says, it's up to the application-use to decide whether or not you want to strip these things out or not.

Anyways, hope that helps ;-)


taxlerendiosk(Posted 2006) [#7]
Bump for a new problem. I'd really like to be able to easily get the line number of XML elements in a document being read, and there are tantalising things like an "xmlLineNumbersDefaultValue" global value and "getParserColumnNumber"/"getParserColumnNumber" methods, but the latter turns out to be completely worthless and I've no idea what else I have to do once setting the former to True (assuming that's what I'm supposed to do). Is it even possible with LibXML?


Brucey(Posted 2006) [#8]
I'll have a look into it :-)


pappavis(Posted 2006) [#9]
any remote chance of XPath / XQuery support?


Brucey(Posted 2006) [#10]
any remote chance of XPath / XQuery support?

Already there...

One of the supplied Tutorials goes into it briefly, and I've only messed around with it a little bit, just to see that it actually works.

And there's also the libxslt module if you wanna get into transformations.


SpaceAce(Posted 2006) [#11]
Whoa, I just opened this thread and didn't even realize it was mine until reading the initial post. I just want to say, Brucey is awesome. Not only does Brucey contribute great modules to our community, he's also fast and friendly with help when us dummies get stuck.

Carry on.

SpaceAce


ninjarat(Posted 2006) [#12]
Yeah. Interestingly enough, he happens to have the same name as my Uncle, who is also an amazing programming genius who provides just this kind of thing...Strange coincidence...