# Generate XML with the xml library

**URL:** <https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194>\
**Category:** Questions & Answers\
**Created:** [October 2, 2024, 9:47am UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194 "2024-10-02T09:47:48Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [October 2, 2024, 9:47am UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/1 "2024-10-02T09:47:48Z")

</div>

hello,

i need to generate an XML document that start with things like that:

```scheme
<?xml version="1.0"?>
<VOTABLE version="1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ivoa.net/xml/VOTable/v1.2" xmlns:stc="http://www.ivoa.net/xml/STC/v1.30" >
  <RESOURCE>
    <TABLE name="getOrbUrl generation">
      <DESCRIPTION>Generation from service getOrbUrl</DESCRIPTION>
      <GROUP ref="" ID="PosFrame">
	<FIELDref ref="col2" utype="stc:AstroCoords.Position3D.Value3.C1"/>

```

i use xml like that:

```scheme
> (xexpr->string `(VOTABLE ((version "1.2") (xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance"))))
(xexpr->string
 `(VOTABLE
   ((version "1.2") (xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance"))))
"<VOTABLE version=\"1.2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"></VOTABLE>"

```

but i did not found a way in the doc to generate the first line:

> \<?xml version="1.0"?\>

is there another way to do it with xml lib ? better than a single display like that:

```scheme
;; create output XML file
	(define out (open-output-file #:exists 'truncate data-out))
	(display "<?xml version=\"1.0\"?>" out)
	(newline out)

```

regards,

damien

---

<div class="post-metadata">

**Author:** ![bakgatviooldoos](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/bakgatviooldoos/32/1381_2.png) [@bakgatviooldoos](https://racket.discourse.group/u/bakgatviooldoos)\
**Post date:** [October 2, 2024, 12:02pm UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/2 "2024-10-02T12:02:06Z")

</div>

Hi, @damien_mattei.

Just a shot in the dark here, but looking at `write-plist` from the `xml` lib, I see this:

```scheme
(define (write-plist xexpr port)
  (write-xml 
   (make-document (make-prolog (list (make-p-i #f #f 'xml "version=\"1.0\" encoding=\"UTF-8\"")) 
                               (make-document-type 'plist
                                                   (make-external-dtd/system
                                                    "http://www.apple.com/DTDs/PropertyList-1.0.dtd")
                                                   #f)
                               empty)
                  (xexpr->xml `(plist ((version "0.9"))
                                      ,(expand-value xexpr)))
                  null)
   port))

```

So maybe `make-document` is the way? I hope that is helpful.

* * *

Edit: I think the `prolog` might actually be the important part? I am ignorant apart from reading this: [XML syntax](https://www.w3schools.com/XML/xml_syntax.asp).

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [October 3, 2024, 9:49am UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/3 "2024-10-03T09:49:01Z")

</div>

it is interesting but for now i'm still searching to make the xml document with that.

I can not find it in the last version of doc , perheaps is it deprecated,  
the [example of the actual doc](https://docs.racket-lang.org/xml/index.html#%28def._%28%28lib._xml%2Fplist..rkt%29._write-plist%29%29) is different.

when i try to test the other example i have this error:

```scheme
(base) mattei@device-97 src % racket
Welcome to Racket v8.13 [cs].
> (require xml)
> (define xexpr `(VOTABLE ((version "1.2") (xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance"))))
> (make-document (make-prolog (list (make-p-i #f #f 'xml "version=\"1.0\" encoding=\"UTF-8\"")) 
                                 (make-document-type 'plist
                                                     (make-external-dtd/system
                                                      "http://www.apple.com/DTDs/PropertyList-1.0.dtd")
                                                     #f)
                                 empty)
                    (xexpr->xml `(plist ((version "0.9"))
                                        ,(expand-value xexpr)))
                    null)
expand-value: undefined;
 cannot reference an identifier before its definition
  in module: top-level
 [,bt for context]
> (xexpr->xml `(plist ((version "0.9"))
                                          ,(expand-value xexpr)))
expand-value: undefined;
 cannot reference an identifier before its definition
  in module: top-level
 [,bt for context]

```

i cannot find reference to expand-value in the current Racket doc.

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [October 3, 2024, 9:57am UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/4 "2024-10-03T09:57:19Z")

</div>

@bakgatviooldoos thank you it works when removing the undefined expand-value:

```scheme
(write-xml
 (make-document
  (make-prolog
   (list (make-p-i #f #f 'xml "version=\"1.0\" encoding=\"UTF-8\""))
   (make-document-type
    'plist
    (make-external-dtd/system "http://www.apple.com/DTDs/PropertyList-1.0.dtd")
    #f)
   empty)
  (xexpr->xml `(plist ((version "0.9")) ,xexpr))
  null))

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="0.9"><VOTABLE version="1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></VOTABLE></plist>#<eof>

```

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [October 3, 2024, 12:47pm UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/5 "2024-10-03T12:47:28Z")

</div>

oh i did not understand it was not an example but probably the source code of write-plist...

---

<div class="post-metadata">

**Author:** ![bakgatviooldoos](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/bakgatviooldoos/32/1381_2.png) [@bakgatviooldoos](https://racket.discourse.group/u/bakgatviooldoos)\
**Post date:** [October 3, 2024, 3:10pm UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/6 "2024-10-03T15:10:40Z")

</div>

Haha, I apologize, I did not mean to pass this off as mine own. I should have linked to the code, but I was simply looking at the files in my editor.

I am glad you have made progress, though.

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [October 18, 2024, 1:30pm UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/7 "2024-10-18T13:30:00Z")

</div>

i just post the code as example of creating XML with xml library and using Schme+ for Racket , not so often i can use racket at work and i used too [Scheme+](https://pkgs.racket-lang.org/package/Scheme-PLUS-for-Racket) for this : given a data text file the goal was to generate an XML file, the input data looks like this :

```scheme
# BepiColombo Mio Orbit after insertion
# Extracted from Sae Aizawa in ~ 2021 
# One sample per minute
# Modified by F. Lavorenti in Oct. 2022
# index X [Rm] Y [Rm] Z [Rm]
0.000000	-5.226162	-0.133805	1.462782
1.000000	-5.239695	-0.133871	1.446325
2.000000	-5.253049	-0.133932	1.429818
3.000000	-5.266226	-0.133988	1.413263
4.000000	-5.279225	-0.134038	1.396661
5.000000	-5.292047	-0.134083	1.380013
6.000000	-5.304692	-0.134123	1.363318
7.000000	-5.317161	-0.134158	1.346578

...

1428.000000	-0.730541	0.029664	-2.397660
1429.000000	-0.680719	0.028417	-2.378984
1430.000000	-0.630639	0.027154	-2.359445
1431.000000	-0.580337	0.025879	-2.339026
1432.000000	-0.529815	0.024591	-2.317697
1433.000000	-0.479085	0.023290	-2.295427
1434.000000	-0.428158	0.021976	-2.272187
1435.000000	-0.377049	0.020649	-2.247945
1436.000000	-0.325759	0.019309	-2.222663
1437.000000	-0.274306	0.017956	-2.196307
1438.000000	-0.222710	0.016590	-2.168841
1439.000000	-0.170992	0.015211	-2.140229

```

1446 lines in BepiColombo-Mio\_MSO-orbit\_1min\_short.txt  
consisting of [BepiColombo](https://en.wikipedia.org/wiki/BepiColombo) spacecraft trajectory, the position is known at each minute (index) and X,Y,Z are expressed in Mercure radius and will be converted in Km.

here is the code of generateXMLfromTrajectory :

```scheme
#! /usr/bin/env racket
#lang reader SRFI-105

;; parse the Bepi Colombo spacecraft trajectory file text and convert it in XML format

;; Damien MATTEI

;; ./generateXMLfromTrajectory ./BepiColombo-Mio_MSO-orbit_1min_short.txt

(module generateXMLfromTrajectory racket
	
	(require Scheme+)
	
	(require xml
		 (except-in 2htdp/batch-io xexpr?)) ; for: read-lines
	
	;;(require (only-in racket/base [for for-racket]))
	
	(require srfi/19) ; Time Data Types and Procedures

	;; parse the input file from command line
	(define cmd-ln-vect (current-command-line-arguments))

	(define Rm 2439.7) ; Rayon Mercure (km)

	{src <- cmd-ln-vect[0]}
	(display "Input file:")
	(display src)
	(newline)

	;; check we have a .txt file
	{ext <- src[-4 :]} ; try to get the .txt extension
	(display "Extension find:")
	(display ext)
	(newline)

	(when (not (equal? ext ".txt"))
	      (error "Not a text file."))

	;; read all lines
	{input-lines <- (read-lines src)}
	{vl <- (list->vector input-lines)}

	;; find the basename
	{basename <- src[: -4]} ; skip the 4 char of extension

	;; create output file name
	{data-out <- (string-append "../" basename ".xml")}

	;; create output XML file
	(define out (open-output-file #:exists 'truncate data-out))

	{tdl <- vl[5 :]}; TABLEDATA lines, skip the header to go to table data lines

	; convert the index (minute) in days hours minutes
	(define (minutes->days-hours-minutes m) ; minutes
	  {minutes-in-day <- 60 * 24}
	  (define days (quotient m minutes-in-day))
	  {minutes <- m % minutes-in-day} ; partial resting minutes
	  (define hours (quotient minutes 60))
	  {minutes <- minutes % 60} ; final resting minutes
	  (values days hours minutes))

	;; my routine to convert date time in a string using SRFI 19 Time Data Types and Procedures
	(define (my-time->string d h m)
	  (define dt19 (make-date 0 0 m h d 1 2021 0))
	  (string-append (date->string dt19 "~5") ".000")) ; append nanoseconds
   
	
	(define (parse-data-table-lines tdl) ; get a vector of lines

	  (for/list ([tr tdl])
		    
		    {(index-minutes xs ys zs) <- (apply values (string-split tr))}
		    
		    ;; convert from Rm mercury in km
		    (define x (string->number xs))
		    (define y (string->number ys))
		    (define z (string->number zs))
		    {x <- x * Rm}
		    {y <- y * Rm}
		    {z <- z * Rm}
		    {xs <- (number->string x)}
		    {ys <- (number->string y)}
		    {zs <- (number->string z)}
		    
		    {(d h m) <- (minutes->days-hours-minutes (inexact->exact (round (string->number index-minutes))))}
		    
		    (define dt-str (my-time->string {d + 1} h m))
		    
		    `(TR (TD ,dt-str)
			  (TD ,xs)
			  (TD ,ys)
			  (TD ,zs))))

	
	
	(define xexpr `(VOTABLE ((version "1.2")
				 (xmlns:xsi "http://www.w3.org/2001/XMLSchema-instance")
				 (xmlns:stc "http://www.ivoa.net/xml/STC/v1.30"))
				(RESOURCE
				 (TABLE ((name "getOrbUrl generation"))
					(DESCRIPTION ,{string-append(vl[0] vl[1] vl[2] vl[3])})
					(GROUP ((ref "")
						(ID "PosFrame"))
					       (FIELDref ((ref "col2")
							  (utype "stc:AstroCoords.Position3D.Value3.C1")))
					       (FIELDref ((ref "col3")
							  (utype "stc:AstroCoords.Position3D.Value3.C2")))
					       (FIELDref ((ref "col4")
							  (utype "stc:AstroCoords.Position3D.Value3.C3"))))
					(FIELD ((name "Time")
						(ID "col1")
						(ucd "time.epoch")
						(xtype "dateTime")
						(utype "")
						(datatype "char")
						(arraysize "*")))
					(FIELD ((name "X")
						(ID "col2")
						(ucd "pos.cartesian.x")
						(utype "stc:AstroCoords.Position3D.Value3.C1")
						(datatype "float")
						(width "10") (unit "km")))
					(FIELD ((name "Y")
						(ID "col3")
						(ucd "pos.cartesian.y")
						(utype "stc:AstroCoords.Position3D.Value3.C2")
						(datatype "float")
						(width "10") (unit "km")))
					(FIELD ((name "Z")
						(ID "col4")
						(ucd "pos.cartesian.z")
						(utype "stc:AstroCoords.Position3D.Value3.C3")
						(datatype "float")
						(width "10") (unit "km")))
					(DATA
					 (TABLEDATA ,@(parse-data-table-lines tdl)))))))

	;; this is the main code
	
	(display-xml
	 (make-document
	  (make-prolog
	   ;;(list (make-p-i #f #f 'xml "version=\"1.0\" encoding=\"UTF-8\""))
	   (list (make-p-i #f #f 'xml "version=\"1.0\""))
	   ;; (make-document-type
	   ;; 'plist
	   ;; (make-external-dtd/system "http://www.apple.com/DTDs/PropertyList-1.0.dtd")
	   ;; #f)
	   #f
	   empty)
	  ;;(xexpr->xml `(plist ((version "0.9")) ,xexpr))
	  (xexpr->xml xexpr)
	  null)
	 out)
	  

	
) ; end module

```

and here is a part of the output XML file generated (BepiColombo-Mio\_MSO-orbit\_1min\_short.xml) :

```scheme
<?xml version="1.0"?>

<VOTABLE version="1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:stc="http://www.ivoa.net/xml/STC/v1.30">
  <RESOURCE>
    <TABLE name="getOrbUrl generation">
      <DESCRIPTION>
        # BepiColombo Mio Orbit after insertion# Extracted from Sae Aizawa in ~ 2021 # One sample per minute# Modified by F. Lavorenti in Oct. 2022
      </DESCRIPTION>
      <GROUP ref="" ID="PosFrame">
        <FIELDref ref="col2" utype="stc:AstroCoords.Position3D.Value3.C1">
        </FIELDref>
        <FIELDref ref="col3" utype="stc:AstroCoords.Position3D.Value3.C2">
        </FIELDref>
        <FIELDref ref="col4" utype="stc:AstroCoords.Position3D.Value3.C3">
        </FIELDref>
      </GROUP>
      <FIELD name="Time" ID="col1" ucd="time.epoch" xtype="dateTime" utype="" datatype="char" arraysize="*">
      </FIELD>
      <FIELD name="X" ID="col2" ucd="pos.cartesian.x" utype="stc:AstroCoords.Position3D.Value3.C1" datatype="float" width="10" unit="km">
      </FIELD>
      <FIELD name="Y" ID="col3" ucd="pos.cartesian.y" utype="stc:AstroCoords.Position3D.Value3.C2" datatype="float" width="10" unit="km">
      </FIELD>
      <FIELD name="Z" ID="col4" ucd="pos.cartesian.z" utype="stc:AstroCoords.Position3D.Value3.C3" datatype="float" width="10" unit="km">
      </FIELD>
      <DATA>
        <TABLEDATA>
          <TR>
            <TD>
              2021-01-01T00:00:00.000
            </TD>
            <TD>
              -12750.2674314
            </TD>
            <TD>
              -326.4440585
            </TD>
            <TD>
              3568.7492454
            </TD>
          </TR>
          <TR>
            <TD>
              2021-01-01T00:01:00.000
            </TD>
            <TD>
              -12783.2838915
            </TD>
            <TD>
              -326.6050787
            </TD>
            <TD>
              3528.5991025
            </TD>
          </TR>
          <TR>
            <TD>
              2021-01-01T00:02:00.000
            </TD>
            <TD>
              -12815.863645299998
            </TD>
            <TD>
              -326.75390039999996
            </TD>
            <TD>
              3488.3269745999996
            </TD>
          </TR>
          <TR>
            <TD>
              2021-01-01T00:03:00.000
            </TD>
            <TD>
              -12848.011572199997
            </TD>
            <TD>
              -326.89052359999994
            </TD>
            <TD>
              3447.9377410999996
            </TD>
          </TR>

...

         <TR>
            <TD>
              2021-01-01T23:57:00.000
            </TD>
            <TD>
              -669.2243481999999
            </TD>
            <TD>
              43.8072532
            </TD>
            <TD>
              -5358.3301879
            </TD>
          </TR>
          <TR>
            <TD>
              2021-01-01T23:58:00.000
            </TD>
            <TD>
              -543.3455869999999
            </TD>
            <TD>
              40.474623
            </TD>
            <TD>
              -5291.3213877
            </TD>
          </TR>
          <TR>
            <TD>
              2021-01-01T23:59:00.000
            </TD>
            <TD>
              -417.16918239999995
            </TD>
            <TD>
              37.1102767
            </TD>
            <TD>
              -5221.5166913
            </TD>
          </TR>
        </TABLEDATA>
      </DATA>
    </TABLE>
  </RESOURCE>
</VOTABLE>

```

---

<div class="post-metadata">

**Author:** ![bakgatviooldoos](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/bakgatviooldoos/32/1381_2.png) [@bakgatviooldoos](https://racket.discourse.group/u/bakgatviooldoos)\
**Post date:** [October 18, 2024, 1:32pm UTC](https://racket.discourse.group/t/generate-xml-with-the-xml-library/3194/8 "2024-10-18T13:32:44Z")

</div>

`+1` for using `Racket` at work! 🥳
