[REBOL] Re: Control Functions and Functionals in Rebol
From: joel:neely:fedex at: 17-May-2001 19:19
Hi, Charlie,
Charles Wardell wrote:
> Does anyone have an example on how to open an xml file and
> iterate through the elements using parse-xml or something.
>
> Thanks,
> Charlie
>
Here's a sample xml file:
8<------------------------------------------------------------
<test date="17-May-2001"
author="Joel Neely">
<desktop color="brown">
<computer mfg="HP"
model="Vectra"
/>
<computer mfg="Compaq"
mode="Presario"
/>
<coffeecup
level="0.5"
/>
</desktop>
<floor color="green">
<chair fabric="blue"
rolling="yes">
<myself name="Joel" />
</chair>
<filingcabinet drawers="4" />
<trashcan liner="yes">
<stickynote color="pink">
somebody else's unreadable
handwritten scribbled message...
</stickynote>
</trashcan>
</floor>
</test>
8<------------------------------------------------------------
Note: the goofy spacing is *NOT* recommended XML style! I just
put it in to demonstrate that the functions below are working
correctly.
PARSE-XML translates each XML element into a block of length 3.
The first item is the element's (tag's) name as a string. The
second is a block of attribute data (name/value pairs) or NONE
if there were no attributes. The third is a block holding all
of the element's content or NONE if the element was an empty
element. All content strings (including whitespace between
tags!) are shown in the content block of the appropriate
element.
The entire document is represented by a similar block; the name
is replaced with the word! DOCUMENT , there are no attributes,
and the content has a single element block for the root element
of the document.
The DUMP-XML-BLOCK function produces a structured display of
the "raw" internal format, with attribute blocks as blocks
and all the ignorable-whitespace intact.
The DUMP-XML function re-renders the internal format as XML,
cleaned up and consistently indented.
The TRIM-XML function cleans up an internal block structure,
deleting ignorable-whitespace content and eliminating empty
content blocks if nothing but ignorable-whitespace was there.
A console transcript illustrates DUMP-XML-BLOCK and DUMP-XML
at work, using the above xml document.
8<------------------------------------------------------------
>> doc: parse-xml read %test.xml
== [document none [["test" ["date" "17-May-2001" "author"
Joel Neely
] ["^/ " ["desktop" ["color" "brown"] ["^/ "
["computer" ...
>> xu: do %xml-utils.r
>> xu/dump-xml-block doc
document
none
[
"test"
["date" "17-May-2001" "author" "Joel Neely"]
[
"^/ "
"desktop"
["color" "brown"]
[
"^/ "
"computer"
["mfg" "HP" "model" "Vectra"]
none
"^/ "
"computer"
["mfg" "Compaq" "mode" "Presario"]
none
"^/ "
"coffeecup"
["level" "0.5"]
none
"^/ "
]
"^/ "
"floor"
["color" "green"]
[
"^/ "
"chair"
["fabric" "blue" "rolling" "yes"]
[
"^/ "
"myself"
["name" "Joel"]
none
"^/ "
]
"^/ "
"filingcabinet"
["drawers" "4"]
none
"^/ "
"trashcan"
["liner" "yes"]
[
"^/ "
"stickynote"
["color" "pink"]
[
{
somebody else's unreadable
handwritten scribbled message...
}
]
"^/ "
]
"^/ "
]
"^/"
]
]
>> xu/dump-xml doc
<test date="17-May-2001" author="Joel Neely">
<desktop color="brown">
<computer mfg="HP" model="Vectra"/>
<computer mfg="Compaq" mode="Presario"/>
<coffeecup level="0.5"/>
</desktop>
<floor color="green">
<chair fabric="blue" rolling="yes">
<myself name="Joel"/>
</chair>
<filingcabinet drawers="4"/>
<trashcan liner="yes">
<stickynote color="pink">
somebody else's unreadable
handwritten scribbled message...
</stickynote>
</trashcan>
</floor>
</test>
>>
8<------------------------------------------------------------
The functions described above are contained in a single file
which is organized for use with the UHURU unit management
system under development (hint, hint, hint...).
8<------------------------------------------------------------
REBOL [
title: {xml-utils}
file: %xml-utils.r
author: {Joel Neely}
version: 1.0.0
comments: {to be added Real Soon Now...}
]
make object! [
trim-xml: func [xml-blk [block!] /local content item] [
if found? content: third xml-blk [
while [not tail? content] [
either block? item: first content [
trim-xml item
content: next content
][
either 0 = length? trim item [
remove content
][
content: next content
]
]
]
if 0 = length? head content [xml-blk/3: none]
]
xml-blk
]
attr-text: func [attribs [block! none!] /local str] [
str: copy ""
if block? attribs [
foreach [attr val] attribs [
append str rejoin [" " attr "=" mold val]
]
]
str
]
open-tag: func [xml-blk [block!]] [
rejoin ["<" to-string xml-blk/1 attr-text xml-blk/2 ">"]
]
empty-tag: func [xml-blk [block!]] [
rejoin ["<" to-string xml-blk/1 attr-text xml-blk/2 "/>"]
]
close-tag: func [xml-blk [block!]] [
rejoin ["</" to-string xml-blk/1 ">"]
]
dump-xml-block: func [xml-blk [block!] /local dump1 pref indent] [
pref: copy ""
indent: " "
dump1: func [xml-blk [block!]] [
print join pref mold xml-blk/1
print join pref mold xml-blk/2
either none? xml-blk/3 [
print join pref mold xml-blk/3
][
print join pref "["
append pref indent
foreach cont xml-blk/3 [
either block? cont [
dump1 cont
][
print join pref mold cont
]
]
print join remove/part pref length? indent "]"
]
]
dump1 xml-blk
]
dump-xml: func [xml-blk [block!] /local dump1 pref indent] [
pref: copy ""
indent: " "
dump1: func [xml-blk [block!]][
either none? xml-blk/3 [
print join pref empty-tag xml-blk
][
print join pref open-tag xml-blk
append pref indent
foreach cont xml-blk/3 [
either block? cont [
dump1 cont
][
foreach item parse/all cont "^/" [
print join pref item
]
]
]
print join remove/part pref length? indent close-tag
xml-blk
]
]
dump1 first third trim-xml copy/deep xml-blk
]
]
8<------------------------------------------------------------
Hope this helps!
-jn-