Hi all,
in the current PB version 4.30, FormatXML() does not work like several people expect, see e.g. this thread.
So here is an alternative way of saving formatted XML to a file.
The code of the prodedure SaveFormattedXml() was modified and improved by me after code by Thorsten.
SaveFormattedXml() preserves leading and trailing whitespace in the text of the XML nodes.
Enjoy!
Little John
//edit 2009-03-18:
- Added: Support for empty elements of the form <item/>.
- Added: Support for node type #PB_XML_Instruction.
- Changed: Simplified the code.
//edit 2009-08-09:
- Fixed: Leading or trailing whitespace is not removed from the text of the XML nodes anymore.
- Fixed: Code changed, so that it now also works as part of Unicode executables.
- Added: Improved error handling.
- Added: Option for saving the respective BOM to the output file.
- Changed: Demo code slightly altered.
Code: Select all
Procedure.i SaveFormattedXml (xmlId, xmlFile$, flags=0, indentStep=3)
Protected *buffer, encoding, size, ofn, Lpos, Rpos, indent=0
Protected xml$, prevLeft$, prevRight$, txt$, curTag$
; Initialize
If IsXML(xmlId) = 0
ProcedureReturn 0 ; error
EndIf
encoding = GetXMLEncoding(xmlId)
size = ExportXMLSize(xmlId)
*buffer = AllocateMemory(size)
If *buffer = 0
ProcedureReturn 0 ; error
EndIf
If ExportXML(xmlId, *buffer, size) = 0
FreeMemory(*buffer)
ProcedureReturn 0 ; error
EndIf
xml$ = PeekS(*buffer, -1, encoding)
FreeMemory(*buffer)
ofn = CreateFile(#PB_Any, xmlFile$)
If ofn = 0
ProcedureReturn 0 ; error
EndIf
If flags & #PB_XML_StringFormat
WriteStringFormat(ofn, encoding)
EndIf
; Get and write XML declaration
Lpos = FindString(xml$, "<", 1)
Rpos = FindString(xml$, ">", Lpos) + 1
curTag$ = Mid(xml$, Lpos, Rpos-Lpos)
WriteString(ofn, curTag$, encoding)
; Get and write the other elements
Lpos = FindString(xml$, "<", Rpos)
While Lpos
prevLeft$ = Left(curTag$, 2)
prevRight$ = Right(curTag$, 2)
txt$ = Mid(xml$, Rpos, Lpos-Rpos)
If Mid(xml$, Lpos, 9) = "<![CDATA["
Rpos = FindString(xml$, "]]>", Lpos) + 3
Else
Rpos = FindString(xml$, ">", Lpos) + 1
EndIf
curTag$ = Mid(xml$, Lpos, Rpos-Lpos)
If FindString("</<!<?", prevLeft$, 1) = 0 And prevRight$ <> "/>"
If Left(curTag$, 2) = "</" ; <tag>text</tag>
WriteString(ofn, txt$ + curTag$, encoding)
Else ; <tag1><tag2>
indent + indentStep
WriteString(ofn, #LF$ + Space(indent) + curTag$, encoding)
EndIf
Else
If Left(curTag$, 2) = "</" ; </tag2>text</tag1>
If Len(txt$)
WriteString(ofn, #LF$ + Space(indent) + txt$, encoding)
EndIf
indent - indentStep
EndIf
WriteString(ofn, #LF$ + Space(indent) + curTag$, encoding)
EndIf
Lpos = FindString(xml$, "<", Rpos)
Wend
CloseFile(ofn)
ProcedureReturn 1 ; success
EndProcedure
Code: Select all
;-- Demo
EnableExplicit
; XIncludeFile "XML.pbi"
XIncludeFile "neu.pbi"
Define Xml, Main, Item, SubItem
Xml = CreateXML(#PB_Any, #PB_UTF8)
Main = CreateXMLNode(RootXMLNode(Xml))
SetXMLNodeName(Main, "root")
SetXMLNodeText(Main, "XML zoo")
Item = CreateXMLNode(Main, -1, #PB_XML_CData)
SetXMLNodeText(Item, "Did you know: 5 > 3 ?")
Item = CreateXMLNode(Main)
SetXMLNodeName(Item, "item")
SetXMLAttribute(Item, "id", "1")
SetXMLNodeText(Item, "Cat")
Item = CreateXMLNode(Main)
SetXMLNodeName(Item, "item")
SetXMLAttribute(Item, "id", "3")
SetXMLNodeText(Item, "Bird")
SubItem = CreateXMLNode(Item)
SetXMLNodeName(SubItem, "subitem")
SetXMLAttribute(SubItem, "id", "4")
SetXMLNodeText(SubItem, "Cuckoo")
SubItem = CreateXMLNode(Item, -1, #PB_XML_Comment)
SetXMLNodeText(SubItem, " Lives in clocks in the Black Forest ")
Item = CreateXMLNode(Main)
SetXMLNodeName(Item, "item")
SetXMLAttribute(Item, "id", "5")
Item = CreateXMLNode(Main, -1, #PB_XML_Instruction)
SetXMLNodeName(Item, "php")
SetXMLNodeText(Item, "...")
Item = CreateXMLNode(Main)
SetXMLNodeName(Item, "item")
SetXMLAttribute(Item, "id", "6")
SetXMLNodeText(Item, " ")
If SaveFormattedXml(Xml, "animals.xml") = 0
MessageRequester("Error", "Can't save XML file.")
EndIf
FreeXML(Xml)
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<root>
<![CDATA[Did you know: 5 > 3 ?]]>
<item id="1">Cat</item>
<item id="3">
<subitem id="4">Cuckoo</subitem>
<!-- Lives in clocks in the Black Forest -->
Bird
</item>
<item id="5"/>
<?php ...?>
<item id="6"> </item>
XML zoo
</root>