source: 1dwg/trunk/IgorPro/cansasXML.ipf @ 27

Last change on this file since 27 was 27, checked in by prjemian, 13 years ago

fixes #8: renamed SAScollimation/distance to SAScollimation/length in XML Schema
fixes #9: added any element to Idata element

revised graphics , examples, IgorPro? code
need to update wiki resources

File size: 39.5 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=1.05
3
4// file:        cansasXML.ipf
5// author:      Pete R. Jemian <jemian@anl.gov>
6// date:        2008-03-31
7// purpose:  implement an IgorPro file reader to read the canSAS 1-D reduced SAS data in XML files
8//                      adheres to the cansas1d/1.0 standard
9// URL: http://www.smallangles.net/wgwiki/index.php/cansas1d_documentation
10//
11// requires:    IgorPro (http://www.wavemetrics.com/)
12//                              XMLutils - XOP (http://www.igorexchange.com/project/XMLutils)
13
14FUNCTION CS_XmlReader(fileName)
15        //
16        // open a canSAS 1-D reduced SAS XML data file
17        //      returns:
18        //              0 : successful
19        //              -1: XML file not found
20        //              -2: root element is not <SASroot>
21        //              -3: <SASroot> version  is not 1.0
22        //              -4: no <SASentry> elements
23        //
24        STRING fileName
25        STRING origFolder
26        STRING workingFolder = "root:Packages:CS_XMLreader"
27        VARIABLE returnCode
28
29        //
30        // set up a work folder within root:Packages
31        // Clear out any progress/results from previous activities
32        //
33        origFolder = GetDataFolder(1)
34        SetDataFolder root:                                     // start in the root data folder
35        NewDataFolder/O  root:Packages          // good practice
36        KillDataFolder/Z  $workingFolder                // clear out any previous work
37        NewDataFolder/O/S  $workingFolder       // Do all our work in root:XMLreader
38
39        //
40        // Try to open the named XML file (clean-up and return if failure)
41        //
42        VARIABLE fileID
43        STRING/G errorMsg, xmlFile
44        MAKE/T/N=(0,3)/O metadata
45        CS_appendMetaData("xmlFile", "", fileName)
46        xmlFile = fileName
47        fileID = XmlOpenFile(fileName)                  // open and parse the XMLfile
48        IF ( fileID < 0 )
49                SWITCH(fileID)                                  // fileID holds the return code; check it
50                        CASE -1:
51                                errorMsg = fileName + ": failed to parse XML"
52                        BREAK
53                        CASE -2:
54                                errorMsg = fileName + " either not found or cannot be opened for reading"
55                        BREAK
56                ENDSWITCH
57                PRINT errorMsg
58                SetDataFolder $origFolder
59                RETURN(-1)                                              // could not find file
60        ENDIF
61
62        //
63        // index the XML element list
64        //
65        XmlElemList(fileID)                                     // load the elementlist into W_ElementList
66        WAVE/T  W_ElementList                           // This declaration comes _after_ XmlElemList() is called
67
68        // qualify the XML file, don't allow just any ole XML.
69        IF ( CmpStr(W_ElementList[0][3], "SASroot") != 0 )              // deftly avoid namespace
70                errorMsg = fileName + ": root element is not <SASroot>"
71                PRINT errorMsg
72                XmlCloseFile(fileID,0)
73                SetDataFolder $origFolder
74                RETURN(-2)                                              // not a canSAS XML file
75        ENDIF
76
77        // make an index to speed up searching through column 0
78        Make/O/T/N=(DimSize(W_ElementList, 0)) W_ElementList_Col0
79        W_ElementList_Col0 = W_ElementList[p][0]
80        STRING/G nsPre = "", nsStr = ""
81        CS_registerNameSpaces(fileID)                           // to assist XPath construction
82
83        // identify supported versions of canSAS XML standard
84        STRING version
85        version = StringByKey("version", W_ElementList[0][2])
86        CS_appendMetaData("cansas_version", CS_XPath_NS("/SASroot/@version"), version)
87        STRSWITCH(version)     
88        CASE "1.0":                                                     // version 1.0 of the canSAS 1-D reduced SAS data standard
89                PRINT fileName, "\t\t identified as: cansas1d/1.0 XML file"
90                returnCode = CS_1i_parseXml(fileID)
91                IF (returnCode != 0)
92                        IF (strlen(errorMsg) == 0)
93                                errorMsg = "error while parsing the XML"
94                        ENDIF
95                        PRINT errorMsg
96                        XmlCloseFile(fileID,0)
97                        SetDataFolder $origFolder
98                        RETURN(returnCode)                      // error while parsing the XML
99                ENDIF
100                BREAK
101        CASE "2.0a":                                            // unsupported
102        DEFAULT:                                                        // optional default expression executed
103                errorMsg = fileName + ": <SASroot> version (" + version + ") is not supported"
104                PRINT errorMsg
105                XmlCloseFile(fileID,0)
106                SetDataFolder $origFolder
107                RETURN(-3)                                              // attribute list must include version="1.0"
108        ENDSWITCH
109
110        XmlCloseFile(fileID,0)                                  // now close the file, without saving
111        fileID = -1
112
113        SetDataFolder $origFolder
114        RETURN(0)                                                       // execution finished OK
115END
116
117// ==================================================================
118
119FUNCTION CS_1i_parseXml(fileID)
120        VARIABLE fileID
121        WAVE/T W_ElementList
122        SVAR errorMsg, xmlFile
123        STRING/G Title
124        STRING XPathStr, Title_folder, SASdata_folder
125        STRING SASentryPath, SASdataPath, RunNum
126        VARIABLE i, j, index, SASdata_index, returnCode = 0
127
128        // locate all the SASentry elements
129        CS_simpleXmlListXpath(fileID, "", "/SASroot//SASentry")
130        WAVE/T  W_listXPath
131        // (safer to copy W_listxpath to a local variable and allow for other calls to XMLlistXpath)
132        DUPLICATE/O/T   W_listXPath, SASentryList
133
134        IF (numpnts(SASentryList) < 1)
135                errorMsg = "could not find any SASentry elements in XML file"
136                PRINT errorMsg
137                RETURN(-4)                                              // no <SASentry> elements
138        ENDIF
139
140        // Should we test here for all required elements?  That could be tedious.  And possibly unnecessary.
141
142        // process each SASentry element
143        DUPLICATE/O/T metadata, metadata_file
144        FOR (i = 0; i < numpnts(SASentryList); i += 1)
145                index = CS_findElementIndex(SASentryList[i])
146                DUPLICATE/O/T metadata_file, metadata
147                Title = CS_1i_locateTitle(fileID, CS_correctedXpathStr(SASentryList[i]))                // look in several places or use default title
148                Title_folder = CleanupName(Title, 0)
149                IF ( CheckName(Title_folder, 11) != 0 )
150                        Title_folder = UniqueName(Title_folder, 11, 0)
151                ENDIF
152                NewDataFolder/O  $Title_folder
153                STRING/G FolderList = ""
154                FolderList = AddListItem(":"+Title_folder+":", FolderList, ";", Inf)
155                //
156                // CS_correctedXpathStr
157                SASentryPath = CS_correctedXpathStr(SASentryList[i])
158                CS_1i_collectMetadata(fileID, SASentryPath)
159                //
160                // next, extract each SASdata block into a subfolder
161                CS_simpleXmlListXpath(fileID, SASentryPath, "//SASdata")        //output: W_listXPath
162                DUPLICATE/O/T   W_listXPath, SASdataList
163                IF (numpnts(SASdataList) == 1)
164                        // only one SASdata element, place data waves in Title folder
165                        SASdataPath = CS_correctedXpathStr(SASdataList[0])
166                        SASdata_folder = ":" + Title_folder + ":"
167                        RunNum = "/Run"
168                        CS_appendMetaData( "Run",                               SASentryPath+CS_XPath_NS(RunNum),                               "")
169                        CS_appendMetaData( "Run_name",                  SASentryPath+CS_XPath_NS(RunNum + "/@name"),    "")
170                        CS_appendMetaData( "SASdata_name",      SASdataPath+CS_XPath_NS("/@name"),                              "")
171                        PRINT "\t\t dataFolder:", SASdata_folder
172                        CS_1i_fillMetadataTable(fileID)
173                        IF (CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder))
174                                // non-zero return code means an error, message is in errorMsg
175                                // What to do now?
176                                //      Proceed with that knowledge or discard the data folder?
177                                //      Go with the discard for now.
178                                returnCode += 1                         // for later
179                                PRINT "\t\t" + errorMsg
180                                KillDataFolder/Z $Title_folder          // only 1 SASdata
181                                // RETURN(1)                            // Can't return now.  What about other SASentry elements?
182                                BREAK
183                        ENDIF
184                ELSE
185                        // multiple SASdata elements, place data waves in subfolders
186                        DUPLICATE/O/T metadata, metadata_entry
187                        FOR (j = 0; j < numpnts(SASdataList); j += 1)
188                                DUPLICATE/O/T metadata_entry, metadata
189                                SASdata_index = CS_findElementIndex(SASdataList[j])
190                                SASdataPath = CS_correctedXpathStr(SASdataList[j])
191                                SASdata_folder = CleanupName(StringByKey("name", W_ElementList[SASdata_index][2]), 0)
192                                PRINT "\t\t dataFolder:", SASdata_folder
193                                RunNum = "/Run["+num2str(j+1)+"]"
194                                CS_appendMetaData( "Run"+num2str(j),                            SASdataPath+"/.."+CS_XPath_NS(RunNum),                          "")
195                                CS_appendMetaData( "Run"+num2str(j)+"_name",            SASdataPath+"/.."+CS_XPath_NS(RunNum + "/@name"),       "")
196                                CS_appendMetaData( "SASdata"+num2str(j)+"_name",        SASdataPath+CS_XPath_NS("/@name"),                                      "")
197                                SetDataFolder $Title_folder
198                                IF ( CheckName(SASdata_folder, 11) != 0 )
199                                        SASdata_folder = UniqueName(SASdata_folder, 11, 0)
200                                ENDIF
201                                NewDataFolder/O  $SASdata_folder
202                                SetDataFolder ::
203                                SASdata_folder =  ":" + Title_folder + ":" + SASdata_folder + ":"
204                                FolderList = AddListItem(SASdata_folder, FolderList, ";", Inf)
205                                //---
206                                CS_1i_fillMetadataTable(fileID)
207                                IF (CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder))
208                                        // non-zero return code means an error, message is in errorMsg
209                                        // What to do now?
210                                        //      Proceed with that knowledge or discard the data folder?
211                                        //      Go with the discard for now.
212                                        returnCode += 1                                         // for later
213                                        PRINT "\t\t" + errorMsg
214                                        KillDataFolder/Z $SASdata_folder                // just this SASdata
215                                        // RETURN(1)                                            // Can't return now.  What about other SASentry elements?
216                                        BREAK
217                                ENDIF
218                        ENDFOR  // many SASdata
219                ENDIF                   // 1 or many SASdata
220                MAKE/O/T/N=(3,2) admin
221                admin[0][0] = "xmlFile"
222                admin[0][1] = xmlFile
223                admin[1][0] = "FolderList"
224                admin[1][1] = FolderList
225                admin[2][0] = "numSASdata"
226                admin[2][1] = num2str(numpnts(SASdataList))
227                Title_folder = ":" + Title_folder + ":"
228                MoveWave admin, $Title_folder
229                MoveString FolderList, $Title_folder
230        ENDFOR          // each SASentry
231
232        RETURN(returnCode)
233END
234
235// ==================================================================
236
237FUNCTION CS_1i_collectMetadata(fileID, sasEntryPath)
238        VARIABLE fileID
239        STRING sasEntryPath
240        VARIABLE i
241        WAVE/T metadata
242        STRING suffix = ""
243        STRING value, detailsPath, detectorPath, notePath
244        // collect some metadata
245        // first, fill a table with keywords, and XPath locations, 3rd column will be values
246
247        // handle most <SASsample> fields
248        CS_appendMetaData("sample_ID",                                          sasEntryPath+CS_XPath_NS("/SASsample/ID"), "")
249        CS_appendMetaData("sample_thickness",                           sasEntryPath+CS_XPath_NS("/SASsample/thickness"), "")
250        CS_appendMetaData("sample_thickness_unit",                      sasEntryPath+CS_XPath_NS("/SASsample/thickness/@unit"), "")
251        CS_appendMetaData("sample_transmission",                        sasEntryPath+CS_XPath_NS("/SASsample/transmission"), "")
252        CS_appendMetaData("sample_temperature",                         sasEntryPath+CS_XPath_NS("/SASsample/temperature"), "")
253        CS_appendMetaData("sample_temperature_unit",            sasEntryPath+CS_XPath_NS("/SASsample/temperature/@unit"), "")
254        CS_appendMetaData("sample_position_x",                          sasEntryPath+CS_XPath_NS("/SASsample/position/x"), "")
255        CS_appendMetaData("sample_position_x_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/x/@unit"), "")
256        CS_appendMetaData("sample_position_y",                          sasEntryPath+CS_XPath_NS("/SASsample/position/y"), "")
257        CS_appendMetaData("sample_position_y_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/y/@unit"), "")
258        CS_appendMetaData("sample_position_z",                          sasEntryPath+CS_XPath_NS("/SASsample/position/z"), "")
259        CS_appendMetaData("sample_position_z_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/z/@unit"), "")
260        CS_appendMetaData("sample_orientation_roll",                    sasEntryPath+CS_XPath_NS("/SASsample/orientation/roll"), "")
261        CS_appendMetaData("sample_orientation_roll_unit",               sasEntryPath+CS_XPath_NS("/SASsample/orientation/roll/@unit"), "")
262        CS_appendMetaData("sample_orientation_pitch",           sasEntryPath+CS_XPath_NS("/SASsample/orientation/pitch"), "")
263        CS_appendMetaData("sample_orientation_pitch_unit",      sasEntryPath+CS_XPath_NS("/SASsample/orientation/pitch/@unit"), "")
264        CS_appendMetaData("sample_orientation_yaw",                     sasEntryPath+CS_XPath_NS("/SASsample/orientation/yaw"), "")
265        CS_appendMetaData("sample_orientation_yaw_unit",        sasEntryPath+CS_XPath_NS("/SASsample/orientation/yaw/@unit"), "")
266        // <SASsample><details> might appear multiple times, too!
267        CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASsample//details")      //output: W_listXPath
268        DUPLICATE/O/T   W_listXPath, detailsList
269        suffix = ""
270        FOR (i = 0; i < numpnts(detailsList); i += 1)
271                IF (numpnts(detailsList) > 1)
272                        suffix = num2str(i)
273                ENDIF
274                detailsPath = CS_correctedXpathStr(detailsList[i])
275                CS_appendMetaData("sample_details"+suffix+"_name",      detailsPath+CS_XPath_NS("/@name"), "")
276                CS_appendMetaData("sample_details"+suffix,                      detailsPath, "")
277        ENDFOR
278
279
280        // <SASinstrument>
281        CS_appendMetaData("Instrument_name", sasEntryPath+CS_XPath_NS("/SASinstrument/name"), "")
282        CS_appendMetaData("Instrument_attr_name", sasEntryPath+CS_XPath_NS("/SASinstrument/@name"), "")
283
284        // <SASinstrument><SASsource>
285        CS_appendMetaData("source_name", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/@name"), "")
286        CS_appendMetaData("radiation", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/radiation"), "")
287        CS_appendMetaData("beam_size_name", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/@name"), "")
288        CS_appendMetaData("beam_size_x", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/x"), "")
289        CS_appendMetaData("beam_size_x_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/x/@unit"), "")
290        CS_appendMetaData("beam_size_y", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/y"), "")
291        CS_appendMetaData("beam_size_y_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/y/@unit"), "")
292        CS_appendMetaData("beam_size_z", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/z"), "")
293        CS_appendMetaData("beam_size_z_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/z/@unit"), "")
294        CS_appendMetaData("beam_shape", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_shape"), "")
295        CS_appendMetaData("wavelength", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength"), "")
296        CS_appendMetaData("wavelength_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength/@unit"), "")
297        CS_appendMetaData("wavelength_min", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_min"), "")
298        CS_appendMetaData("wavelength_min_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_min/@unit"), "")
299        CS_appendMetaData("wavelength_max", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_max"), "")
300        CS_appendMetaData("wavelength_max_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_max/@unit"), "")
301        CS_appendMetaData("wavelength_spread", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_spread"), "")
302        CS_appendMetaData("wavelength_spread_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_spread/@unit"), "")
303
304        // ignore <SASinstrument><SAScollimation> for now
305        CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASinstrument//SAScollimation")           //output: W_listXPath
306        DUPLICATE/O/T   W_listXPath, SAScollimationList
307        STRING collimationPath
308        suffix = ""
309        FOR (i = 0; i < numpnts(SAScollimationList); i += 1)
310                IF (numpnts(SAScollimationList) > 1)
311                        suffix = num2str(i)
312                ENDIF
313                collimationPath = CS_correctedXpathStr(SAScollimationList[i])
314                CS_appendMetaData("collimation_name"+suffix,    collimationPath+CS_XPath_NS("/@name"), "")
315                CS_appendMetaData("collimation_length"+suffix,  collimationPath+CS_XPath_NS("/length"), "")
316                CS_appendMetaData("collimation_length_unit"+suffix,     collimationPath+CS_XPath_NS("/length/@unit"), "")
317                CS_appendMetaData("collimation_aperture_name"+suffix,   collimationPath+CS_XPath_NS("/aperture/@name"), "")
318                CS_appendMetaData("collimation_aperture_type"+suffix,   collimationPath+CS_XPath_NS("/aperture/type"), "")
319                CS_appendMetaData("collimation_aperture_size_name"+suffix,      collimationPath+CS_XPath_NS("/aperture/size/@name"), "")
320                CS_appendMetaData("collimation_aperture_size_x"+suffix,         collimationPath+CS_XPath_NS("/aperture/size/x"), "")
321                CS_appendMetaData("collimation_aperture_size_x_unit"+suffix,    collimationPath+CS_XPath_NS("/aperture/size/x/@unit"), "")
322                CS_appendMetaData("collimation_aperture_size_y"+suffix,         collimationPath+CS_XPath_NS("/aperture/size/y"), "")
323                CS_appendMetaData("collimation_aperture_size_y_unit"+suffix,    collimationPath+CS_XPath_NS("/aperture/size/y/@unit"), "")
324                CS_appendMetaData("collimation_aperture_size_z"+suffix,         collimationPath+CS_XPath_NS("/aperture/size/z"), "")
325                CS_appendMetaData("collimation_aperture_size_z_unit"+suffix,    collimationPath+CS_XPath_NS("/aperture/size/z/@unit"), "")
326                CS_appendMetaData("collimation_aperture_distance"+suffix,       collimationPath+CS_XPath_NS("/aperture/distance"), "")
327                CS_appendMetaData("collimation_aperture_distance_unit"+suffix,  collimationPath+CS_XPath_NS("/aperture/distance/@unit"), "")
328        ENDFOR
329
330        // <SASinstrument><SASdetector> might appear multiple times
331        CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASinstrument//SASdetector")      //output: W_listXPath
332        DUPLICATE/O/T   W_listXPath, SASdetectorList
333        suffix = ""
334        FOR (i = 0; i < numpnts(SASdetectorList); i += 1)
335                IF (numpnts(SASdetectorList) > 1)
336                        suffix = num2str(i)
337                ENDIF
338                detectorPath = CS_correctedXpathStr(SASdetectorList[i])
339                CS_appendMetaData("detector_name"+suffix,       detectorPath+CS_XPath_NS("/name"), "")
340                CS_appendMetaData("SDD"+suffix,                         detectorPath+CS_XPath_NS("/SDD"), "")
341                CS_appendMetaData("SDD"+suffix+"_unit",                 detectorPath+CS_XPath_NS("/SDD/@unit"), "")
342                CS_appendMetaData("detector_offset_name"+suffix,        detectorPath+CS_XPath_NS("/offset/@name"), "")
343                CS_appendMetaData("detector_offset_x"+suffix,           detectorPath+CS_XPath_NS("/offset/x"), "")
344                CS_appendMetaData("detector_offset_x_unit"+suffix,      detectorPath+CS_XPath_NS("/offset/x/@unit"), "")
345                CS_appendMetaData("detector_offset_y"+suffix,           detectorPath+CS_XPath_NS("/offset/y"), "")
346                CS_appendMetaData("detector_offset_y_unit"+suffix,      detectorPath+CS_XPath_NS("/offset/y/@unit"), "")
347                CS_appendMetaData("detector_offset_z"+suffix,           detectorPath+CS_XPath_NS("/offset/z"), "")
348                CS_appendMetaData("detector_offset_z_unit"+suffix,      detectorPath+CS_XPath_NS("/offset/z/@unit"), "")
349
350                CS_appendMetaData("detector_orientation_name"+suffix,           detectorPath+CS_XPath_NS("/orientation/@name"), "")
351                CS_appendMetaData("detector_orientation_roll"+suffix,           detectorPath+CS_XPath_NS("/orientation/roll"), "")
352                CS_appendMetaData("detector_orientation_roll_unit"+suffix,      detectorPath+CS_XPath_NS("/orientation/roll/@unit"), "")
353                CS_appendMetaData("detector_orientation_pitch"+suffix,          detectorPath+CS_XPath_NS("/orientation/pitch"), "")
354                CS_appendMetaData("detector_orientation_pitch_unit"+suffix,     detectorPath+CS_XPath_NS("/orientation/pitch/@unit"), "")
355                CS_appendMetaData("detector_orientation_yaw"+suffix,            detectorPath+CS_XPath_NS("/orientation/yaw"), "")
356                CS_appendMetaData("detector_orientation_yaw_unit"+suffix,       detectorPath+CS_XPath_NS("/orientation/yaw/@unit"), "")
357
358                CS_appendMetaData("detector_beam_center_name"+suffix,   detectorPath+CS_XPath_NS("/beam_center/@name"), "")
359                CS_appendMetaData("detector_beam_center_x"+suffix,              detectorPath+CS_XPath_NS("/beam_center/x"), "")
360                CS_appendMetaData("detector_beam_center_x_unit"+suffix,         detectorPath+CS_XPath_NS("/beam_center/x/@unit"), "")
361                CS_appendMetaData("detector_beam_center_y"+suffix,              detectorPath+CS_XPath_NS("/beam_center/y"), "")
362                CS_appendMetaData("detector_beam_center_y_unit"+suffix,         detectorPath+CS_XPath_NS("/beam_center/y/@unit"), "")
363                CS_appendMetaData("detector_beam_center_z"+suffix,              detectorPath+CS_XPath_NS("/beam_center/z"), "")
364                CS_appendMetaData("detector_beam_center_z_unit"+suffix,         detectorPath+CS_XPath_NS("/beam_center/z/@unit"), "")
365
366                CS_appendMetaData("detector_pixel_size_name"+suffix,    detectorPath+CS_XPath_NS("/pixel_size/@name"), "")
367                CS_appendMetaData("detector_pixel_size_x"+suffix,               detectorPath+CS_XPath_NS("/pixel_size/x"), "")
368                CS_appendMetaData("detector_pixel_size_x_unit"+suffix,  detectorPath+CS_XPath_NS("/pixel_size/x/@unit"), "")
369                CS_appendMetaData("detector_pixel_size_y"+suffix,               detectorPath+CS_XPath_NS("/pixel_size/y"), "")
370                CS_appendMetaData("detector_pixel_size_y_unit"+suffix,  detectorPath+CS_XPath_NS("/pixel_size/y/@unit"), "")
371                CS_appendMetaData("detector_pixel_size_z"+suffix,               detectorPath+CS_XPath_NS("/pixel_size/z"), "")
372                CS_appendMetaData("detector_pixel_size_z_unit"+suffix,  detectorPath+CS_XPath_NS("/pixel_size/z/@unit"), "")
373
374                CS_appendMetaData("slit_length"+suffix,                 detectorPath+CS_XPath_NS("/slit_length"), "")
375                CS_appendMetaData("slitLength"+suffix+"_unit",  detectorPath+CS_XPath_NS("/slit_length/@unit"), "")
376        ENDFOR
377
378        // ignore <SASprocess> for now
379
380        // <SASnote> might appear multiple times
381        CS_simpleXmlListXpath(fileID, sasEntryPath, "//SASnote")        //output: W_listXPath
382        DUPLICATE/O/T   W_listXPath, SASnoteList
383        suffix = ""
384        FOR (i = 0; i < numpnts(SASnoteList); i += 1)
385                IF (numpnts(SASnoteList) > 1)
386                        suffix = num2str(i)
387                ENDIF
388                notePath = CS_correctedXpathStr(SASnoteList[i])
389                CS_appendMetaData("SASnote"+suffix+"_name",     notePath+CS_XPath_NS("/@name"), "")
390                CS_appendMetaData("SASnote"+suffix,                             notePath, "")
391        ENDFOR
392        //CS_1i_fillMetadataTable(fileID)
393END
394
395// ==================================================================
396
397FUNCTION/S CS_1i_fillMetadataTable(fileID)
398        VARIABLE fileID
399        WAVE/T metadata
400        VARIABLE i
401        STRING value
402        // +++++++++++++++++++++++++                    // try to fill the value column from the XML data
403        FOR (i = 0; i < DimSize(metadata, 0); i += 1)
404                IF (strlen(metadata[i][1]) > 0)                         // XPathStr for this entry?
405                        IF (strlen(metadata[i][2])  == 0)                       // not defined yet?
406                                value = CS_XmlStrFmXpath(fileID, metadata[i][1], "")            // get it
407                                // What if the value string has a ";" embedded?
408                                //  This will complicate (?compromise?) the wavenote "key=value;" syntax.
409                                metadata[i][2] = ReplaceString(";", value, " :semicolon: ")
410                        ENDIF
411                ENDIF
412        ENDFOR
413END
414
415// ==================================================================
416
417FUNCTION/S CS_1i_locateTitle(fileID, SASentryPath)
418        VARIABLE fileID
419        STRING SASentryPath
420        WAVE/T metadata
421        STRING TitlePath, Title
422        // /SASroot/SASentry/Title is the expected location, but it could be empty
423        TitlePath = SASentryPath+CS_XPath_NS("/Title")
424        Title = CS_XmlStrFmXpath(fileID,  TitlePath, "")
425        // search harder for a title
426        IF (strlen(Title) == 0)
427                TitlePath = SASentryPath+CS_XPath_NS("/@name")
428                Title = CS_XmlStrFmXpath(fileID,  TitlePath, "")
429        ENDIF
430        IF (strlen(Title) == 0)
431                TitlePath = SASentryPath+CS_XPath_NS("/SASsample/ID")
432                Title = CS_XmlStrFmXpath(fileID,  TitlePath, "")
433        ENDIF
434        IF (strlen(Title) == 0)
435                TitlePath = SASentryPath+CS_XPath_NS("/SASsample/@name")
436                Title = CS_XmlStrFmXpath(fileID,  TitlePath, "")
437        ENDIF
438        IF (strlen(Title) == 0)
439                // last resort: make up a title
440                Title = "SASentry"
441                TitlePath = ""
442        ENDIF
443        PRINT "\t Title:", Title
444        CS_appendMetaData("title", TitlePath, Title)
445        RETURN(Title)
446END
447
448// ==================================================================
449
450FUNCTION CS_fileExists(fileName)
451        // checks if a file can be found and opened
452        // !!! not needed by 2008-03-13 change in XmlOpenFile()
453        STRING fileName
454        VARIABLE refNum
455        Open/R/Z/P=home refNum as fileName
456        IF (V_flag == 0)
457                CLOSE refNum
458        ENDIF
459        RETURN( !V_flag )
460END
461
462// ==================================================================
463
464FUNCTION CS_appendMetaData(key, xpath, value)
465        STRING key, xpath, value
466        WAVE/T metadata
467        VARIABLE last
468        last = DimSize(metadata, 0)
469        Redimension/N=(last+1, 3) metadata
470        metadata[last][0] = key
471        metadata[last][1] = xpath
472        metadata[last][2] = value
473END
474
475// ==================================================================
476
477FUNCTION CS_findElementIndex(matchStr)
478        STRING matchStr
479        //
480        // support the canSAS XML file reader
481        // return index where   g[index][0] == matchStr
482        // return -1 if not found
483        //
484        WAVE/T W_ElementList_Col0
485
486        FindValue/TEXT=matchStr    W_ElementList_Col0
487        RETURN(V_value)
488END
489
490// ==================================================================
491
492FUNCTION CS_registerNameSpaces(fileID)
493        VARIABLE fileID
494        //
495        // The canSAS 1-D namespace is defined in the <SASroot> element.
496        // We can use our own namespace prefix without further concern.
497        // Other namespaces may be used in the file but this does not
498        // look for foreign (non-canSAS) elements.
499        //
500        WAVE/T W_ElementList
501        SVAR nsPre
502        SVAR nsStr
503        VARIABLE i, j, index, row
504        STRING testStr
505        MAKE/T/N=(1,2)/O nsRegistry
506        //
507        nsStr = W_ElementList[0][1]             // this is the one to use
508        nsPre = ""
509        IF (strlen(nsStr))
510                nsPre = "cs:"
511                nsStr = "cs=" + nsStr
512        ENDIF
513        // 2008-03-14,PRJ: Now, add a workaround for the libxml2 support that affects MacOS.
514        //   When using namespaces
515        //              W_ElementList[][1] != "" (it shows a namespace for this node)
516        //   and with default libxml2 (v2.2) on MacOS,
517        //              W_ElementList[][0] != /SASroot/SASentry ...
518        //  BUT, on PCs and on MacOS with user-proveded libxml2 (?version?)
519        //              W_ElementList[][0] != /*/*[1]   or /*/* ...
520        //
521        // Need to handle either situation.
522        //  Add another column to W_ElementList that shows the corrected absolute
523        //      XPath query,  complete with namespace prefix as needed.
524        Redimension/N=(DimSize(W_ElementList,0),5) W_ElementList
525        W_ElementList[0,Inf][4] = ""                            // clear out the last column (useful only to developer)
526        W_ElementList[0][4] = CS_XPath_NS("/"+W_ElementList[0][3])
527        FOR (i = 1; i < DimSize(W_ElementList,0); i += 1)
528                IF (strlen(W_ElementList[i][4]) == 0)           // if not already set, then find absolute XPath string
529                        // For now, only handle items in the default namespace.
530                        // Takes more work to build in the capability to handle more namespaces
531                        //
532                        index = CS_findElementIndex(  CS_findLast(W_ElementList[i][0], "/", 1  )  )
533                        testStr = W_ElementList[index][4] + CS_XPath_NS("/"+W_ElementList[i][3])
534                        XMLlistXpath(fileID,testStr,nsStr)
535                        IF ( !EXISTS("W_listXPath") )
536                                PRINT i, testStr, " empty result from XmlListXpath()"
537                                BREAK
538                        ENDIF
539                        WAVE/T W_listXPath
540                        SWITCH(numpnts(W_listXPath))
541                                CASE 0:                 // What?  Can't find the node we just found?
542                                        //PRINT numpnts(W_listXPath), testStr, " !!! WARNING:  <Can't find the node we just found> in CS_registerNameSpaces()"
543                                        PRINT i, testStr, " Foreign element namespace detected and ignored"
544                                        BREAK
545                                CASE 1:                 // Only one node with this element
546                                        W_ElementList[i][4] = testStr
547                                        BREAK
548                                DEFAULT:                        // Multiple elements match this node; need to use indices
549                                        // PRINT numpnts(W_listXPath), testStr
550                                        FOR (j = 0; j < numpnts(W_listXPath); j += 1)
551                                                index = CS_findElementIndex(  W_listXPath[j]  )
552                                                W_ElementList[index][4] = testStr + "[" + num2str(j+1) + "]"
553                                        ENDFOR
554                                        BREAK
555                        ENDSWITCH
556                ENDIF
557        ENDFOR
558        // PRINT StringByKey("schemaLocation", W_ElementList[0][2])
559        //
560        // <code comes here>
561        RETURN(0)
562END
563
564// ==================================================================
565
566FUNCTION/S CS_findLast(src, matchStr, leftSide)
567        STRING src
568        STRING matchStr
569        VARIABLE leftSide
570        // given a source string such as:   /*/*/*[7]/*/*[39]/*[2]
571        // return the part on the $leftSide if the $matchStr
572        // Examples:
573        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "/", 1)                 /*/*/*[7]/*/*[39]
574        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "/", 0)                 /*[2]
575        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "[", 1)                 /*/*/*[7]/*/*[39]/*
576        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "[", 0)                 [2]
577        VARIABLE i
578        STRING result="", test
579        FOR (i=strlen(src)-1; i >= 0; i -= 1)
580                IF (stringmatch(src[i], matchStr ))
581                        IF (leftSide)
582                                result = src[0,i-1]
583                        ELSE
584                                result = src[i,Inf]
585                        ENDIF
586                        RETURN(result)
587                ENDIF
588        ENDFOR
589        RETURN(result)
590END
591
592// ==================================================================
593
594FUNCTION/S CS_XPath_NS(simpleStr)
595        // namespaces complicate the XPath description
596        // this function adds namespace info as necessary to simpleStr (an XPath)
597        STRING simpleStr
598        SVAR nsPre
599        STRING result = "", thisChar, lastChar = ""
600        VARIABLE i
601        FOR (i = 0; i < strlen(simpleStr); i += 1)
602                //PRINT simpleStr[i]
603                thisChar = simpleStr[i]
604                IF ( CmpStr(lastChar, "/") == 0 )
605                        STRSWITCH (thisChar)
606                                CASE "/":
607                                CASE ".":
608                                CASE "@":
609                                        BREAK
610                                DEFAULT:
611                                        result += nsPre
612                        ENDSWITCH
613                ENDIF
614                result += thisChar
615                lastChar = thisChar
616        ENDFOR
617        RETURN(result)
618END
619
620// ==================================================================
621
622FUNCTION/S CS_XmlStrFmXpath(fileID, prefix, value)
623        VARIABLE fileID
624        STRING prefix, value
625        SVAR nsStr
626        STRING result
627        result = TrimWS(XmlStrFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, ""))
628        RETURN( result )
629END
630
631// ==================================================================
632
633FUNCTION CS_simpleXmlWaveFmXpath(fileID, prefix, value)
634        VARIABLE fileID
635        STRING prefix, value
636        SVAR nsStr
637        XMLwaveFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, " ")
638        // output: M_xmlContent  W_xmlContentNodes
639END
640
641// ==================================================================
642
643FUNCTION/S CS_correctedXpathStr(indexPath)
644        STRING indexPath
645        VARIABLE index
646        STRING absolutePath
647        WAVE/T          W_ElementList
648        index  =  CS_findElementIndex(indexPath)
649        absolutePath = W_ElementList[index][4]  // use corrected XPath string
650        RETURN(absolutePath)
651END
652
653// ==================================================================
654
655FUNCTION CS_simpleXmlListXpath(fileID, prefix, value)
656        VARIABLE fileID
657        STRING prefix, value
658        SVAR nsStr
659        XMLlistXpath(fileID, prefix + CS_XPath_NS(value), nsStr)                // output: W_listXPath
660END
661
662// ==================================================================
663
664Function/T   TrimWS(str)
665    // TrimWhiteSpace (code from Jon Tischler)
666    String str
667    str = TrimWSL(str)
668    str = TrimWSR(str)
669    return str
670End
671
672// ==================================================================
673
674Function/T   TrimWSL(str)
675    // TrimWhiteSpaceLeft (code from Jon Tischler)
676    String str
677    Variable i, N=strlen(str)
678    for (i=0;char2num(str[i])<=32 && i<N;i+=1)    // find first non-white space
679    endfor
680    return str[i,Inf]
681End
682
683// ==================================================================
684
685Function/T   TrimWSR(str)
686    // TrimWhiteSpaceRight (code from Jon Tischler)
687    String str
688    Variable i
689    for (i=strlen(str)-1; char2num(str[i])<=32 && i>=0; i-=1)    // find last non-white space
690    endfor
691    return str[0,i]
692End
693
694// ==================================================================
695
696FUNCTION CS_updateWaveNote(wavName, key, value)
697        STRING wavName, key, value
698        STRING wavenote
699        wavenote = ReplaceStringByKey(key, note($wavName), value)
700        Note /K $wavName, wavenote
701END
702
703// ==================================================================
704
705FUNCTION CS_1i_extractIdataColumn2Wave(fileID, basePath, colName, wavName)
706        //
707        // this function pulls one column of data from each <Idata> element
708        // easier to write this as a function than debug it all the times it is needed
709        //
710        VARIABLE fileID
711        STRING basePath, colName, wavName
712        STRING unit
713        WAVE/T metadata
714        VARIABLE i, numPts
715
716        //      Q values come out in multiple columns. Different nodes means different columns in M_xmlcontent
717        //      Multiple values in the SAME node (i.e. a vector) get put in different rows.
718        //      We are therefore going to transpose the wave
719        //      (Based on example from Andrew R.J. Nelson.)
720        CS_simpleXmlWaveFmXpath(fileID, basePath, "//Idata/" + colName)
721        WAVE/T  M_xmlcontent, W_xmlcontentnodes
722        numPts = numpnts(M_XMLcontent)
723        IF (numPts > 0)
724                MatrixTranspose M_XMLcontent
725                MAKE/O/D/N=(numpnts(M_XMLcontent)) $wavName = str2num(M_xmlcontent[p][0])
726                // don't forget the units!  Assume that all rows have the same "unit" as in the first row.
727                unit = CS_XmlStrFmXpath(fileID, basePath, "/Idata[1]/"+colName+"/@unit")
728                SetScale d 0, 1, unit, $wavName                         // update the wave's "UNITS" string
729                SetScale x 0, 1, unit, $wavName                         // put it here, too, for the Data Browser
730                // put unit directly into wavenote of _this_ wave
731                CS_updateWaveNote(wavName, "unit", unit)                // put UNIT in wavenote
732                // store all the metadata in the wavenote (for now, at least)
733                FOR (i = 0; i < DimSize(metadata, 0); i += 1)
734                        IF (strlen(metadata[i][2]) > 0)
735                                // only add defined metadata to the wavenote
736                                CS_updateWaveNote(wavName, metadata[i][0], metadata[i][2])
737                        ENDIF
738                ENDFOR
739        ELSE
740                // did not find any data
741                // no need to apply special handling here; do that in the caller
742        ENDIF
743        //IF (numPts)
744        //      PRINT "\t\t\t\t" + wavName + ": found " + num2str(numPts) + " points"
745        //ENDIF
746        RETURN(numPts)
747END
748
749// ==================================================================
750
751FUNCTION CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder)
752        //
753        // extract data from the SASdata/Idata block in a canSAS1d/v1.0 XML file
754        //  (1i in the function name signifies this is a function that supports INPUT from version 1.0 XML files)
755        //
756        //      returns:
757        //              0       no error
758        //              1       number of points in waves is not the same as Qsas wave
759        //
760        VARIABLE fileID
761        STRING SASdataPath, SASdata_folder
762        WAVE/T metadata
763        VARIABLE numPts, numQ
764        SVAR errorMsg
765
766        // extract each Idata column into waves
767        // ignore the return codes here, check below
768        numQ    = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Q",                       "Qsas")
769        IF (numQ != CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "I",                     "Isas"))
770                errorMsg = "number of points in Qsas and Isas waves are not identical"
771                RETURN(1)
772        ENDIF
773        numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Idev",             "Idev")
774        IF (numPts && (numQ != numPts) )
775                errorMsg = "number of points in Qsas and Idev waves are not identical"
776                RETURN(1)
777        ENDIF
778        numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qdev",             "Qdev")
779        IF (numPts && (numQ != numPts) )
780                errorMsg = "number of points in Qsas and Qdev waves are not identical"
781                RETURN(1)
782        ENDIF
783        numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "dQw",              "dQw")
784        IF (numPts && (numQ != numPts) )
785                errorMsg = "number of points in Qsas and dQw waves are not identical"
786                RETURN(1)
787        ENDIF
788        numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "dQl",                      "dQl")
789        IF (numPts && (numQ != numPts) )
790                errorMsg = "number of points in Qsas and dQl waves are not identical"
791                RETURN(1)
792        ENDIF
793        numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qmean",            "Qmean")
794        IF (numPts && (numQ != numPts) )
795                errorMsg = "number of points in Qsas and Qmean waves are not identical"
796                RETURN(1)
797        ENDIF
798        numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Shadowfactor",     "Shadowfactor")
799        IF (numPts && (numQ != numPts) )
800                errorMsg = "number of points in Qsas and Shadowfactor waves are not identical"
801                RETURN(1)
802        ENDIF
803
804        PRINT "\t\t\t\t found " + num2str(numpnts(Qsas)) + " points"
805
806        // move the waves to the sample folder
807        // !!!!! Missing Qsas, Isas, Qdev, and/or Idev are a broken data set
808        //              This should produce an exception.  Should have been trapped by numPts tests.
809        //              Best to return an error code but the caller chain is not ready to pass that to the top level, yet.
810        MoveWave Qsas, $SASdata_folder                          // required wave
811        MoveWave Isas, $SASdata_folder                          // required wave
812        IF (exists("Idev") == 1)
813                MoveWave Idev, $SASdata_folder                  // optional wave
814        ENDIF
815        IF (exists("Qdev") == 1)
816                MoveWave Qdev, $SASdata_folder                  // optional wave
817        ENDIF
818        IF (exists("dQw") == 1)
819                MoveWave dQw, $SASdata_folder                   // optional wave
820        ENDIF
821        IF (exists("dQl") == 1)
822                MoveWave dQl, $SASdata_folder                   // optional wave
823        ENDIF
824        IF (exists("Qmean") == 1)
825                MoveWave Qmean, $SASdata_folder         // optional wave
826        ENDIF
827        IF (exists("ShadowFactor") == 1)
828                MoveWave ShadowFactor, $SASdata_folder  // optional wave
829        ENDIF
830        IF (exists("metadata") == 1)
831                Duplicate/O metadata, $SASdata_folder + "metadata"
832        ENDIF
833        RETURN(0)                       // no error
834END
835
836
837// ==================================================================
838// ==================================================================
839// ==================================================================
840
841
842FUNCTION prj_grabMyXmlData()
843        STRING srcDir = "root:Packages:CS_XMLreader"
844        STRING destDir = "root:PRJ_canSAS"
845        STRING srcFolder, destFolder, theFolder
846        Variable i
847        NewDataFolder/O  $destDir               // for all my imported data
848        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 )
849                theFolder = GetIndexedObjName(srcDir, 4, i)
850                srcFolder = srcDir + ":" + theFolder
851                destFolder = destDir + ":" + theFolder
852                // PRINT srcFolder, destFolder
853                IF (DataFolderExists(destFolder))
854                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
855                        // need to find unique name for destination
856                        // Persons who implement this properly should be more elegant
857                        // For now, I will blast the existing and proceed blindly.
858                        KillDataFolder/Z  $destFolder           // clear out any previous work
859                        DuplicateDataFolder $srcFolder, $destFolder
860                ELSE
861                        DuplicateDataFolder $srcFolder, $destFolder
862                ENDIF
863        ENDFOR
864END
865
866FUNCTION prjTest_cansas1d()
867        // unit tests for the routines under prj-readXML.ipf
868        STRING theFile
869        STRING fList = ""
870        VARIABLE i, result, timerID, seconds
871        // build a table of test data sets
872        fList = AddListItem("elmo.xml",                                 fList, ";", Inf)                // non-existent file
873        fList = AddListItem("cansasXML.ipf",                    fList, ";", Inf)                // this file (should fail on XML parsing)
874        fList = AddListItem("book.xml",                                 fList, ";", Inf)                // good XML example file but not canSAS, not even close
875        fList = AddListItem("bimodal-test1.xml",                fList, ";", Inf)                // simple dataset
876        fList = AddListItem("bimodal-test2-vector.xml", fList, ";", Inf)                // version 2.0 file (no standard yet)
877        fList = AddListItem("test.xml",                                 fList, ";", Inf)                // cs_collagen.xml with no namespace
878        fList = AddListItem("test2.xml",                                fList, ";", Inf)                // version 2.0 file (no standard yet)
879        fList = AddListItem("ISIS_SANS_Example.xml",    fList, ";", Inf)                // from S. King, 2008-03-17
880        fList = AddListItem("W1W2.xml",                                 fList, ";", Inf)                // from S. King, 2008-03-17
881        fList = AddListItem("ill_sasxml_example.xml",   fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
882        fList = AddListItem("isis_sasxml_example.xml",  fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
883        fList = AddListItem("r586.xml",                                         fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
884        fList = AddListItem("r597.xml",                                         fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
885        fList = AddListItem("xg009036_001.xml",                 fList, ";", Inf)                // foreign elements with other namespaces
886        fList = AddListItem("cs_collagen.xml",                  fList, ";", Inf)                // another simple dataset, bare minimum info
887        fList = AddListItem("cs_collagen_full.xml",             fList, ";", Inf)                // more Q range than previous
888        fList = AddListItem("cs_af1410.xml",                    fList, ";", Inf)                // multiple SASentry and SASdata elements
889        fList = AddListItem("cansas1d-template.xml",    fList, ";", Inf)                // multiple SASentry and SASdata elements
890        //fList = AddListItem("1998spheres.xml",                        fList, ";", Inf)                // 2 SASentry, few thousand data points each
891        fList = AddListItem("does-not-exist-file.xml",          fList, ";", Inf)                // non-existent file
892        fList = AddListItem("cs_rr_polymers.xml",               fList, ";", Inf)                // Round Robin polymer samples from John Barnes @ NIST
893        // try to load each data set in the table
894        FOR ( i = 0; i < ItemsInList(fList) ; i += 1 )
895                theFile = StringFromList(i, fList)                                      // walk through all test files
896                // PRINT "file: ", theFile
897                pathInfo home
898                //IF (CS_XmlReader(theFile) == 0)                                       // did the XML reader return without an error code?
899                timerID = StartMStimer
900                result = CS_XmlReader(ParseFilePath(5,S_path,"*",0,0) + theFile)
901                seconds = StopMSTimer(timerID) * 1.0e-6
902                PRINT "\t Completed in ", seconds, " seconds"
903                IF (result == 0)    // did the XML reader return without an error code?
904                        prj_grabMyXmlData()                                             // move the data to my directory
905                ENDIF
906        ENDFOR
907END
908
909
910FUNCTION prjTest_writer(xmlFile)
911        STRING xmlFile
912        VARIABLE fileID
913        STRING nsStr = "cansas1d/1.0", prefixStr = ""
914        fileID = XMLcreateFile(xmlFile,"SASroot",nsStr,prefixStr)
915        XMLsetAttr(fileID,              "/SASroot",                             nsStr, "version", "1.0")
916        XMLsetAttr(fileID,              "/SASroot",                             nsStr, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
917        XMLsetAttr(fileID,              "/SASroot",                             nsStr, "xsi:schemaLocation", "cansas1d/1.0    http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd")
918        XMLaddNode(fileID,      "/SASroot",                             nsStr, "SASentry", "", 1)
919        XMLsetAttr(fileID,              "/SASroot/SASentry",    nsStr, "name", "something")
920        XMLaddNode(fileID,      "/SASroot/SASentry",    nsStr, "Title", "my very first title", 1)
921        XMLaddNode(fileID,      "/SASroot/SASentry",    nsStr, "Run", "2008-03-19", 1)
922        XMLsetAttr(fileID,              "/SASroot/SASentry/Run", nsStr, "name", "actually is a date")
923        XMLsaveFile(fileID)
924        XMLcloseFile(fileID,0)
925END
Note: See TracBrowser for help on using the repository browser.