Script Library: 1221 scripts
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Documentation for: rebelxml.r


REBOL

RebelXML - User Manual

Version: 1.2
Date: 28-apr-06
Author: Christophe Coussement (COU)
Contact: reboltof-at-yahoo-dot-com

Contents:

1. What is RebelXML ?
2. What do I need to run RebelXML ?
3. Extracting data from XML data
3.1 The function 'load-xml-data
3.2 The function 'get-xml-data
3.3 Usage example 1: using tags
3.4 Usage exemple 2: using attributes
4. Creating a XML data from scratch
4.1 The function 'set-xml-data
4.2 The function 'clear-xml-data
4.3 The function 'show-xml-data
4.4 The function 'set-xml-quote
4.5 Usage example
5. Modifiying existing XML data
5.1 Usage example
6. Supplementary note: Unit test used for script validation

History:

Date

Version

Description

Author

28-avr-05

1.2

Correct typo (thanks to 10djé !)

COU

27-avr-05

1.1

Add Unit tests examples

COU

25-avr-05

1.0

Initial

COU


Warning

RebelXML is currently a BETA version, released in the purpose of getting feedbacks and bugs reports from the users.

Avoid to use this script into a production environnement, as certain key-functionnalities could be changed.

This documentation has no pretention of being complete, and will be reworked as the feedbacks come and the project is being developped.

1. What is RebelXML ?

RebXML is a SAX-like XML access-functions library, which allows the user to read/write/create/delete XML data in a very easy way.

RebXML works directly with the XML data, without the need of any to REBOL block convertion, because it uses the great power of the REBOL parser.

2. What do I need to run RebelXML ?

1. Download the script %RebelXML.r from http://www.rebol.org

2. Be sure you're running REBOL/View >= 1.3 and launch the console

3. Run the script into the console:

do %RebelXML.r

or include it into a script

4. Use the functions described into this document

3. Extracting data from XML data

3.1 The function 'load-xml-data

USAGE:

LOAD-XML-DATA data

DESCRIPTION:

load xml data into xml-data word LOAD-XML-DATA is a function value

ARGUMENTS:

data -- XML data to load (Type: string)

3.2 The function 'get-xml-data

USAGE:

GET-XML-DATA path /content /attribute att-name /with-attribute w-att-name w-att-data

DESCRIPTION:

extract requested data from xml GET-XML-DATA is a function value.

ARGUMENTS:

path -- the path pointing to the data (Type: path word)

REFINEMENTS:

/content -- if content value is requested

/attribute -- if attribute value is requested

att-name -- name of the attribute (Type: word)

/with-attribute -- qualify a content

w-att-name -- name of the attribute (Type: word)

w-att-data -- value of the attribute (Type: string)

3.3 Usage example 1: using tags

Let start with this simple example...

Consider this simple XML code example (from http://www.w3schools.com/xml/xml_examples.asp), placed into the file %note.xml:

<note>
  <to>Tove</to> 
  <from>Jani</from> 
  <heading>Reminder</heading> 
  <body>Don't forget me this weekend!</body>
</note>

And we want to extract the 'to' and 'from' information... Proceed as following:

1. Run the script into the console:

>> do %RebelXML.r

2. Load the XML code into RebelXML:

The XML code must be loaded as a string!

>> load-xml-data read %note.xml
== {<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</not...

3. Extract the desired information from the XML code:

>> get-xml-data/content 'note/to
== ["Tove"]
>> get-xml-data/content 'note/from
== ["Jani"]

Using the /content refinement, you specify to RebelXMl that you are interested into the content of the tag, not anything else. Simple, isn't it ?

3.4 Usage exemple 2: using attributes

Let's consider the file %note.xml, containing multiple notes, each one identified by an unique identifier 'id':

<messages>
    <note id="p501">
        <to>Tove</to>
        <from>Jani</from>
        <heading>Reminder</heading>
        <body>Don't forget me this weekend!</body>
    </note>    
    <note id="p502">
        <to>Jani</to>
        <from>Tove</from>
        <heading>Re: Reminder</heading>
        <body>I will not!</body>
    </note> 
</messages>

We are only interested in the values contained into the note 'p502'. To extract those specific information, we've to specify the required attribute:

>> load-xml-data read %note.xml
== {    <messages>
  <note id="p501">
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
 ...
>> get-xml-data/content/with-attribute 'messages/note 'id "p502"
== [{
        <to>Jani</to>
        <from>Tove</from>
        <heading>Re: Reminder</heading>
        <body>I will not!</body>
    ...

If we are searching for more specific information, let's say the field 'to', we've to proceed in 2 requests:

>> load-xml-data read %note.xml
== {    <messages>
  <note id="p501">
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
 ...
 >> load-xml-data first get-xml-data/content/with-attribute 'messages/note 'id "p502"
== {
        <to>Jani</to>
        <from>Tove</from>
        <heading>Re: Reminder</heading>
        <body>I will not!</body>
     ...
 >> get-xml-data/content 'to
 == ["Jani"]

Perhaps do we want to know which id's are available into our XML data ? Let do this:

>> load-xml-data read %note.xml
== {    <messages>
  <note id="p501">
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>
 ...
 >> get-xml-data/attribute 'note 'id
 == ["p501" "p502"]

4. Creating a XML data from scratch

The base idea is quite simple: if you try to write something at the end of a path wich does not exists yet, RebelXML will construct it for you !

You can use those functions to proceed:

4.1 The function 'set-xml-data

USAGE:

SET-XML-DATA path /content data /attribute att-name att-value /with-attribute w-att-name w-att-data

DESCRIPTION:

set path, content and/or attribute into xml-data SET-XML-DATA is a function value.

ARGUMENTS:

path -- access path (Type: word path)

REFINEMENTS:

/content -- set a content

data -- content data (Type: string)

/attribute -- set an attribute

att-name -- attribute name (Type: word) att-value -- attribute data (Type: string)

/with-attribute -- specify a tag with a given attribute

w-att-name -- name of the attribute (Type: word) w-att-data -- value of the attribute (Type: string)

4.2 The function 'clear-xml-data

USAGE:

CLEAR-XML-DATA

DESCRIPTION:

clears existing data into internal cache CLEAR-XML-DATA is a function value.

4.3 The function 'show-xml-data

USAGE:

SHOW-XML-DATA

DESCRIPTION:

returns data from internal cache SHOW-XML-DATA is a function value

4.4 The function 'set-xml-quote

USAGE:

SET-XML-QUOTE user-quote

DESCRIPTION:

set user quote preference (default is 'simple) SET-XML-QUOTE is a function value.

ARGUMENTS:

user-quote -- May be 'simple or 'double (Type: word)

4.5 Usage example

As illustration, let's try to reconstitue the "note" we used in the preceding part of this documentation:

To begin from a healthy base, let's clear the buffer:

>> clear-xml-data
== ""

And add the tags and data we need:

>> set-xml-data/content 'note/body "Don't forget me this weekend!"
== {<note><body>Don't forget me this weekend!</body></note>}
>> set-xml-data/content 'note/heading "Reminder"
== {<note><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>}
>> set-xml-data/content 'note/from "Jani"
== {<note><from>Jani</from><heading>Reminder</heading><body>Don't forget
me this weekend!</body></note>}
>> set-xml-data/content 'note/to "Tove"
== {<note><to>Tove</to><from>Jani</from><heading>Reminder</heading>
<body>Don't forget me this weekend!</body></note>}

and we can get the generated content by using 'show-xml-data:

>> show-xml-data
== {<note><to>Tove</to><from>Jani</from><heading>Reminder</heading>
<body>Don't forget me this weekend!</body></note>}

or, if indented:

{<note>
  <to>Tove</to> 
  <from>Jani</from> 
  <heading>Reminder</heading> 
  <body>Don't forget me this weekend!</body>
</note>}

Caution

Because RebelXML is inserting the new tags into the existing data, we need to insert first the last data of the set, if the tag order matters. A way to easily handle this is shown next to this.

We could also use a more "REBOLish" code and write:

>> data: [
[        'note/to "Tove"
[        'note/from "Jani"
[        'note/heading "Reminder"
[        'note/body "Don't forget me this weekend!"
[    ]
== [
    'note/to "Tove"
    'note/from "Jani"
    'note/heading "Reminder"
    'note/body "Don't forget me this weekend!"
]
>> reverse data
== ["Don't forget me this weekend!"
    'note/body "Reminder"
    'note/heading "Jani"
    'note/from "Tove"
    'note/to
]
>> foreach [content tag] data [set-xml-data/content tag content]
== {<note><to>Tove</to><from>Jani</from><heading>Reminder</heading>
<body>Don't forget me this weekend!</body></note>}

5. Modifiying existing XML data

The same 'set-xml-data function can be used for modifying existing contents.

5.1 Usage example

Let's start from our note:

>> load-xml-data read %note.xml
== {<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</not...

And modify the existing "Tove" into "Frebus":

>> set-xml-data/content 'note/to "Frebus"
== {    <messages>
      <note>
        <to>Frebus</to>
        <from>Jani</from>
        <heading>Reminder</heading>
        <body...
>> probe show-xml-data
{    <messages>
      <note>
        <to>Frebus</to>
        <from>Jani</from>
        <heading>Reminder</heading>
        <body>Don't forget me this weekend!</body>
      </note>
    </messages>
}

6. Supplementary note: Unit test used for script validation

For those who are curious to know what "Test Driven Development" is, here is an example of some tests I used for the validation of the function 'set-xml-data.

Note

You will need the %RUn.r script for trying those unit tests. You can find it at: http://www.rebol.org/cgi-bin/cgiwrap/rebol/view-script.r?script=run.r

;===  UNIT TEST ===
;========================
;=== TASK X2.1 - set-data ===
;===========================================================================
;--- set test context
setup: does [
    #include %RebelXML.r
]
;===========================================================================
;--- create new path
test-set-data-1a: does [
    assert set-xml-data/content 'result/section/section "test"
]
;--- 
test-set-data-1b: does [
   assert-equal show-xml-data {<result><section><section>test</section></section></result>}
]
;--- complete partial path w
test-set-data-2a: does [
   load-xml-data {<result><section></section></result>}
   assert set-xml-data/content 'result/section/item/time "20"
]
test-set-data-2b: does [
   assert-equal show-xml-data {<result><section><item><time>20</time></item></section></result>}
]
;---
test-set-data-3a: does [
    assert set-xml-data/content 'result/section/section/date "26-jan-06"
]
test-set-data-3b: does [
   assert-equal show-xml-data {<result><section><section><date>26-jan-06</date></section><item><time>20</time></item></section></result>}
]
test-set-data-4a: does [
    load-xml-data {<result><section></section></result>}
    assert set-xml-data/attribute 'result/section 'ident "20103"
]
test-set-data-4b: does [
   assert-equal show-xml-data {<result><section ident='20103'></section></result>}
]
test-set-data-4c: does [
    assert set-xml-data/attribute 'result/section 'type "file"
]
test-set-data-4d: does [
   assert-equal show-xml-data {<result><section type='file' ident='20103'></section></result>}
]
test-set-data-4e: does [
    load-xml-data {<result><section></section></result>}
    set-xml-quote 'double
    assert set-xml-data/attribute 'result/section 'ident "20103"
]
test-set-data-4f: does [
    assert-equal show-xml-data {<result><section ident="20103"></section></result>}   
]
test-set-data-5a: does [
    load-xml-data {<result><section type='file' ident='20103'></section><section type='file' ident='20104'></section></result>}
    set-xml-quote 'simple
    assert set-xml-data/content/with-attribute 'result/section "test" 'ident "20104"  
]
test-set-data-5b: does [
    assert-equal show-xml-data {<result><section type='file' ident='20103'></section><section type='file' ident='20104'>test</section></result>}
]
test-set-data-6a: does [
    load-xml-data {<result><test>test content<section>section content</section></result>}
    assert set-xml-data/content 'result/section "new content"
]
test-set-data-6b: does [
    assert-equal show-xml-data {<result><test>test content<section>new content</section></result>}
]
;===========================================================================
;--- clean up test context
teardown: does []
;===========================================================================
MakeDoc2 by REBOL- 28-Apr-2006