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

Last change on this file since 54 was 54, checked in by ajj, 13 years ago

Fixed wave naming bug in CS_1i_GetReducedSASdata(). dQl was being written to Qsas wave.

File size: 35.2 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=1.08
3
4// file:        cansasXML.ipf
5// author:      Pete R. Jemian <jemian@anl.gov>
6// date:        2008-06-02
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// readme:    http://www.smallangles.net/wgwiki/index.php/cansas1d_binding_IgorPro
10// URL: http://www.smallangles.net/wgwiki/index.php/cansas1d_documentation
11//
12// requires:    IgorPro (http://www.wavemetrics.com/)
13//                              XMLutils - XOP (http://www.igorexchange.com/project/XMLutils)
14
15// ==================================================================
16// CS_XmlReader("bimodal-test1.xml")
17// CS_XmlReader("1998spheres.xml")
18// CS_XmlReader("xg009036_001.xml")
19// CS_XmlReader("s81-polyurea.xml")
20// CS_XmlReader("cs_af1410.xml")
21//  testCollette();  prjTest_cansas1d()
22// ==================================================================
23
24
25FUNCTION CS_XmlReader(fileName)
26        //
27        // open a canSAS 1-D reduced SAS XML data file
28        //      returns:
29        //              0 : successful
30        //              -1: XML file not found
31        //              -2: root element is not <SASroot> with valid canSAS namespace
32        //              -3: <SASroot> version  is not 1.0
33        //              -4: no <SASentry> elements
34        //              -5: XOPutils needs upgrade
35        //
36        STRING fileName
37        STRING origFolder
38        STRING workingFolder = "root:Packages:CS_XMLreader"
39        VARIABLE returnCode
40
41        //
42        // set up a work folder within root:Packages
43        // Clear out any progress/results from previous activities
44        //
45        origFolder = GetDataFolder(1)
46        SetDataFolder root:                                     // start in the root data folder
47        NewDataFolder/O  root:Packages          // good practice
48        KillDataFolder/Z  $workingFolder                // clear out any previous work
49        NewDataFolder/O/S  $workingFolder       // Do all our work in root:XMLreader
50
51        //
52        // Try to open the named XML file (clean-up and return if failure)
53        //
54        VARIABLE fileID
55        STRING/G errorMsg, xmlFile
56        xmlFile = fileName
57        fileID = XmlOpenFile(fileName)                  // open and parse the XMLfile
58        IF ( fileID < 0 )
59                SWITCH(fileID)                                  // fileID holds the return code; check it
60                        CASE -1:
61                                errorMsg = fileName + ": failed to parse XML"
62                        BREAK
63                        CASE -2:
64                                errorMsg = fileName + " either not found or cannot be opened for reading"
65                        BREAK
66                ENDSWITCH
67                PRINT errorMsg
68                SetDataFolder $origFolder
69                RETURN(-1)                                              // could not find file
70        ENDIF
71
72        //
73        //      test to see if XOPutils has the needed upgrade
74        //
75        XMLlistXpath(fileID, "/*", "") 
76        IF ( EXISTS( "M_listXPath" ) == 0 )
77                XmlCloseFile(fileID,0)
78                errorMsg = "XOPutils needs an upgrade:  http://www.igorexchange.com/project/XMLutils"
79                PRINT errorMsg
80                SetDataFolder $origFolder
81                RETURN(-5)                                              // XOPutils needs an upgrade
82        ENDIF
83        WAVE/T  M_listXPath
84
85        // check for canSAS namespace string, returns "" if not valid or not found
86        STRING/G ns = CS_getDefaultNamespace(fileID)
87        IF (strlen(ns) == 0 )
88                XmlCloseFile(fileID,0)
89                errorMsg = "root element is not <SASroot> with valid canSAS namespace"
90                PRINT errorMsg
91                SetDataFolder $origFolder
92                RETURN(-2)                                              // root element is not <SASroot> with valid canSAS namespace
93        ENDIF
94        STRING/G nsPre = "cs:"
95        STRING/G nsStr = "cs=" + ns
96
97        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
98        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
99       
100        STRSWITCH(ns)   
101        CASE "cansas1d/1.0":                                                    // version 1.0 of the canSAS 1-D reduced SAS data standard
102                PRINT fileName, "\t\t identified as: cansas1d/1.0 XML file"
103                returnCode = CS_1i_parseXml(fileID)                     //  This is where the action happens!
104                IF (returnCode != 0)
105                        IF (strlen(errorMsg) == 0)
106                                errorMsg = "error while parsing the XML"
107                        ENDIF
108                        PRINT errorMsg
109                        XmlCloseFile(fileID,0)
110                        SetDataFolder $origFolder
111                        RETURN(returnCode)                      // error while parsing the XML
112                ENDIF
113                BREAK
114        CASE "cansas1d/2.0a":                                           // unsupported
115        DEFAULT:                                                        // optional default expression executed
116                errorMsg = fileName + ": <SASroot>, namespace (" + ns + ") is not supported"
117                PRINT errorMsg
118                XmlCloseFile(fileID,0)
119                SetDataFolder $origFolder
120                RETURN(-3)                                              // attribute list must include version="1.0"
121        ENDSWITCH
122
123        XmlCloseFile(fileID,0)                                  // now close the file, without saving
124        fileID = -1
125
126        SetDataFolder root:Packages:CS_XMLreader
127        KillWaves/Z M_listXPath, SASentryList
128        SetDataFolder $origFolder
129        RETURN(0)                                                       // execution finished OK
130END
131
132FUNCTION/S CS_getDefaultNamespace(fileID)
133        // Test here (by guessing) for the various known namespaces.
134        // Return the one found in the "schemaLocation" attribute
135        // since the XMLutils XOP does not provide any xmlns attributes.
136        // It is possible to call XMLelemList and get the namespace directly
137        // but that call can be expensive (time) when there are lots of elements.
138        VARIABLE fileID
139        STRING ns = "", thisLocation
140        VARIABLE i, item
141        MAKE/T/N=(1)/O nsList           // list of all possible namespaces
142        nsList[0] = "cansas1d/1.0"              // first version of canSAS 1-D reduced SAS
143
144        FOR (item = 0; item < DimSize(nsList, 0); item += 1)            // loop over all possible namespaces
145                XMLlistAttr(fileID, "/cs:SASroot", "cs="+nsList[item])
146                WAVE/T M_listAttr
147                FOR (i = 0; i < DimSize(M_listAttr,0); i+=1)                    // loop over all available attributes
148                        // Expect the required canSAS XML header (will fail if "schemalocation" is not found)
149                        IF ( CmpStr(  LowerStr(M_listAttr[i][1]),  LowerStr("schemaLocation") ) == 0 )
150                                thisLocation = TrimWS(M_listAttr[i][2])
151                                IF ( StringMatch(thisLocation, nsList[item] + "*") )
152                                        ns = nsList[item]
153                                        BREAK           // found it!
154                                ENDIF
155                        ENDIF
156                ENDFOR
157                IF (strlen(ns))
158                        BREAK           // found it!
159                ENDIF
160        ENDFOR
161
162        KillWaves/Z nsList, M_listAttr
163        RETURN ns
164END
165
166// ==================================================================
167
168FUNCTION CS_1i_parseXml(fileID)
169        VARIABLE fileID
170        SVAR errorMsg, xmlFile
171        STRING/G Title, Title_folder
172        VARIABLE i, j, index, SASdata_index, returnCode = 0
173
174        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
175        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
176
177        // locate all the SASentry elements
178        //      assume nsPre = "cs" otherwise
179        // "/"+nsPre+":SASroot//"+nsPre+":SASentry"
180        XmlListXpath(fileID, "/cs:SASroot//cs:SASentry", nsStr)
181        WAVE/T  M_listXPath
182        STRING          SASentryPath
183        DUPLICATE/O/T   M_listXPath, SASentryList
184
185        FOR (i=0; i < DimSize(SASentryList, 0); i += 1)
186                SASentryPath = "/cs:SASroot/cs:SASentry["+num2str(i+1)+"]"
187                SetDataFolder root:Packages:CS_XMLreader
188               
189                title =  CS_1i_locateTitle(fileID, SASentryPath)
190                Title_folder = CS_cleanFolderName(Title)
191                NewDataFolder/O/S  $Title_folder
192
193                XmlListXpath(fileID, SASentryPath + "//cs:SASdata", nsStr)
194                WAVE/T  M_listXPath
195                IF ( DimSize(M_listXPath, 0) == 1)
196                        CS_1i_getOneSASdata(fileID, Title, SASentryPath+"/cs:SASdata")
197                        CS_1i_collectMetadata(fileID, SASentryPath)
198                ELSE
199                        FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)
200                                STRING SASdataFolder = CS_cleanFolderName("SASdata_" + num2str(j))
201                                NewDataFolder/O/S  $SASdataFolder
202                                CS_1i_getOneSASdata(fileID, Title, SASentryPath+"/cs:SASdata["+num2str(j+1)+"]")
203                                CS_1i_collectMetadata(fileID, SASentryPath)
204                                SetDataFolder ::                        // back up to parent directory
205                        ENDFOR
206                ENDIF
207                KillWaves/Z M_listXPath
208        ENDFOR
209
210        SetDataFolder root:Packages:CS_XMLreader
211        KillWaves/Z M_listXPath, SASentryList
212        RETURN(returnCode)
213END
214
215// ==================================================================
216
217FUNCTION/S CS_cleanFolderName(proposal)
218        STRING proposal
219        STRING result
220        result = CleanupName(proposal, 0)
221        IF ( CheckName(result, 11) != 0 )
222                result = UniqueName(result, 11, 0)
223        ENDIF
224        RETURN result
225END
226
227// ==================================================================
228
229FUNCTION CS_1i_getOneSASdata(fileID, Title, SASdataPath)
230        VARIABLE fileID
231        STRING Title, SASdataPath
232        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
233        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
234        VARIABLE i
235        STRING SASdata_name, suffix = ""
236
237        //grab the data and put it in the working data folder
238        CS_1i_GetReducedSASdata(fileID, SASdataPath)
239
240        //start the metadata
241        MAKE/O/T/N=(0,2) metadata
242
243        SVAR xmlFile = root:Packages:CS_XMLreader:xmlFile
244        CS_appendMetaData(fileID, "xmlFile", "", xmlFile)
245
246        SVAR ns = root:Packages:CS_XMLreader:ns
247        CS_appendMetaData(fileID, "namespace", "", ns)
248        CS_appendMetaData(fileID, "Title", "", Title)
249       
250        XmlListXpath(fileID, SASdataPath + "/..//cs:Run", nsStr)
251        WAVE/T  M_listXPath
252        FOR (i=0; i < DimSize(M_listXPath, 0); i += 1)
253                IF ( DimSize(M_listXPath, 0) > 1 )
254                        suffix = "_" + num2str(i)
255                ENDIF
256                CS_appendMetaData(fileID, "Run" + suffix,  SASdataPath + "/../cs:Run["+num2str(i+1)+"]", "")
257                CS_appendMetaData(fileID, "Run/@name" + suffix,  SASdataPath + "/../cs:Run["+num2str(i+1)+"]/@name", "")
258        ENDFOR
259
260        SASdata_name = TrimWS(XMLstrFmXpath(fileID,  SASdataPath + "/@name", nsStr, ""))
261        CS_appendMetaData(fileID, "SASdata/@name", "", SASdata_name)
262
263        KillWaves/Z M_listXPath
264END
265
266// ==================================================================
267
268FUNCTION CS_1i_getOneVector(file,prefix,XML_name,Igor_name)
269        VARIABLE file
270        STRING prefix,XML_name,Igor_name
271        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
272        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
273
274        XmlWaveFmXpath(file,prefix+XML_name,nsStr,"")                   //this loads ALL the vector's nodes at the same time
275        WAVE/T M_xmlcontent
276        WAVE/T W_xmlContentNodes
277        IF (DimSize(M_xmlcontent, 0))                   // test to see if the nodes exist.  not strictly necessary if you know the nodes are there
278                IF (DimSize(M_xmlcontent,1)>DimSize(M_xmlcontent,0))    //if you're not in vector mode
279                        MatrixTranspose M_xmlcontent
280                ENDIF
281                MAKE/O/D/N=(DimSize(M_xmlcontent, 0)) $Igor_name
282                WAVE vect = $Igor_name
283                vect=str2num(M_xmlcontent)
284        ENDIF
285        KILLWAVES/Z M_xmlcontent, W_xmlContentNodes
286END
287
288// ==================================================================
289
290FUNCTION CS_1i_GetReducedSASdata(fileID, SASdataPath)
291        VARIABLE fileID
292        STRING SASdataPath
293        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
294        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
295        STRING prefix = ""
296        VARIABLE pos
297
298        VARIABLE cansasStrict = 1               // !!!software developer's choice!!!
299        IF (cansasStrict)               // only get known canSAS data vectors
300                prefix = SASdataPath + "//cs:"
301                // load ALL nodes of each vector (if exists) at tthe same time
302                CS_1i_getOneVector(fileID, prefix, "Q",                 "Qsas")
303                CS_1i_getOneVector(fileID, prefix, "I",                 "Isas")
304                CS_1i_getOneVector(fileID, prefix, "Idev",              "Idev")
305                CS_1i_getOneVector(fileID, prefix, "Qdev",              "Qdev")
306                CS_1i_getOneVector(fileID, prefix, "dQw",       "dQw")
307                CS_1i_getOneVector(fileID, prefix, "dQl",               "dQl")
308                CS_1i_getOneVector(fileID, prefix, "Qmean",     "Qmean")
309                CS_1i_getOneVector(fileID, prefix, "Shadowfactor",      "Shadowfactor")
310                // check them for common length
311        ELSE                            // search for _ANY_ data vectors
312                // find the names of all the data columns and load them as vectors
313                // this gets tricky if we want to avoid namespace references
314                XmlListXpath(fileID, SASdataPath+"//cs:Idata[1]/*", nsStr)
315                WAVE/T M_listXPath
316                STRING xmlElement, xPathStr
317                STRING igorWave
318                VARIABLE j
319                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)        // loop over all columns in SASdata/Idata[1]
320                        xmlElement = M_listXPath[j][1]
321                        STRSWITCH(xmlElement)
322                                CASE "Q":               // IgorPro does not allow a variable named Q
323                                CASE "I":                       // or I
324                                        igorWave = xmlElement + "sas"
325                                        BREAK
326                                DEFAULT:
327                                        igorWave = xmlElement           // can we trust this one?
328                        ENDSWITCH
329                        //
330//                      // This will need some work to support foreign namespaces here
331//                      //
332//                      //
333//                      xPathStr = M_listXPath[j][0]                                                    // clear name reference
334//                      pos = strsearch(xPathStr, "/", Inf, 3)                                  // peel off the tail of the string and reform
335//                      xmlElement = xPathStr[pos,Inf]                                          // find last element on the path
336//                      prefix = xPathStr[0, pos-1-4]+"/*"                                              // ALL Idata elements
337//                      CS_1i_getOneVector(fileID,prefix, xmlElement, igorWave)         // loads ALL rows (Idata) of the column at the same time
338                        //
339                        //  Could there be a problem with a foreign namespace here?
340                        prefix = SASdataPath+"//cs:Idata"                                               // ALL Idata elements
341                        xmlElement = "cs:" + M_listXPath[j][1]                                  // just this column
342                        CS_1i_getOneVector(fileID,prefix, xmlElement, igorWave)         // loads ALL rows (Idata) of the column at the same time
343                ENDFOR
344                // check them for common length
345        ENDIF
346 
347        //get rid of any mess
348        KILLWAVES/z M_listXPath
349END
350
351// ==================================================================
352
353FUNCTION CS_1i_collectMetadata(fileID, sasEntryPath)
354        VARIABLE fileID
355        STRING sasEntryPath
356        VARIABLE i, j
357        WAVE/T metadata
358        STRING suffix = "", preMeta = "", preXpath = ""
359        STRING value, detailsPath, detectorPath, notePath
360
361        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
362        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
363
364        // collect some metadata
365        // first, fill a table with keywords, and XPath locations, 3rd column will be values
366
367        // handle most <SASsample> fields
368        CS_appendMetaData(fileID, "SASsample/@name",                            sasEntryPath + "/cs:SASsample/@name", "")
369        CS_appendMetaData(fileID, "SASsample/ID",                                       sasEntryPath + "/cs:SASsample/cs:ID", "")
370        CS_appendMetaData(fileID, "SASsample/thickness",                                sasEntryPath + "/cs:SASsample/cs:thickness", "")
371        CS_appendMetaData(fileID, "SASsample/thickness/@unit",                  sasEntryPath + "/cs:SASsample/cs:thickness/@unit", "")
372        CS_appendMetaData(fileID, "SASsample/transmission",                     sasEntryPath + "/cs:SASsample/cs:transmission", "")
373        CS_appendMetaData(fileID, "SASsample/temperature",                      sasEntryPath + "/cs:SASsample/cs:temperature", "")
374        CS_appendMetaData(fileID, "SASsample/temperature/@unit",           sasEntryPath + "/cs:SASsample/cs:temperature/@unit", "")
375        CS_appendMetaData(fileID, "SASsample/position/x",                          sasEntryPath + "/cs:SASsample/cs:position/cs:x", "")
376        CS_appendMetaData(fileID, "SASsample/position/x/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:x/@unit", "")
377        CS_appendMetaData(fileID, "SASsample/position/y",                          sasEntryPath + "/cs:SASsample/cs:position/cs:y", "")
378        CS_appendMetaData(fileID, "SASsample/position/y/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:y/@unit", "")
379        CS_appendMetaData(fileID, "SASsample/position/z",                          sasEntryPath + "/cs:SASsample/cs:position/cs:z", "")
380        CS_appendMetaData(fileID, "SASsample/position/z/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:z/@unit", "")
381        CS_appendMetaData(fileID, "SASsample/orientation/roll",                    sasEntryPath + "/cs:SASsample/cs:orientation/cs:roll", "")
382        CS_appendMetaData(fileID, "SASsample/orientation/roll/@unit",      sasEntryPath + "/cs:SASsample/cs:orientation/cs:roll/@unit", "")
383        CS_appendMetaData(fileID, "SASsample/orientation/pitch",           sasEntryPath + "/cs:SASsample/cs:orientation/cs:pitch", "")
384        CS_appendMetaData(fileID, "SASsample/orientation/pitch/@unit",     sasEntryPath + "/cs:SASsample/cs:orientation/cs:pitch/@unit", "")
385        CS_appendMetaData(fileID, "SASsample/orientation/yaw",                     sasEntryPath + "/cs:SASsample/cs:orientation/cs:yaw", "")
386        CS_appendMetaData(fileID, "SASsample/orientation/yaw/@unit",       sasEntryPath + "/cs:SASsample/cs:orientation/cs:yaw/@unit", "")
387        // <SASsample><details> might appear multiple times, too!
388        XmlListXpath(fileID, sasEntryPath+"/cs:SASsample//cs:details", nsStr)   //output: M_listXPath
389        WAVE/T  M_listXPath
390        DUPLICATE/O/T   M_listXPath, detailsList
391        suffix = ""
392        FOR (i = 0; i < DimSize(detailsList, 0); i += 1)
393                IF (DimSize(detailsList, 0) > 1)
394                        suffix = "_" + num2str(i)
395                ENDIF
396                detailsPath = sasEntryPath+"/cs:SASsample/cs:details["+num2str(i+1)+"]"
397                CS_appendMetaData(fileID, "SASsample/details"+suffix+"/@name",  detailsPath + "/@name", "")
398                CS_appendMetaData(fileID, "SASsample/details"+suffix,           detailsPath, "")
399        ENDFOR
400
401
402        // <SASinstrument>
403        CS_appendMetaData(fileID, "SASinstrument/name",         sasEntryPath + "/cs:SASinstrument/cs:name", "")
404        CS_appendMetaData(fileID, "SASinstrument/@name",        sasEntryPath + "/cs:SASinstrument/@name", "")
405
406        // <SASinstrument><SASsource>
407        preMeta = "SASinstrument/SASsource"
408        preXpath = sasEntryPath + "/cs:SASinstrument/cs:SASsource"
409        CS_appendMetaData(fileID, preMeta + "/@name",                      preXpath + "/@name", "")
410        CS_appendMetaData(fileID, preMeta + "/radiation",                  preXpath + "/cs:radiation", "")
411        CS_appendMetaData(fileID, preMeta + "/beam/size/@name",            preXpath + "/cs:beam_size/@name", "")
412        CS_appendMetaData(fileID, preMeta + "/beam/size/x",                preXpath + "/cs:beam_size/cs:x", "")
413        CS_appendMetaData(fileID, preMeta + "/beam/size/x@unit",           preXpath + "/cs:beam_size/cs:x/@unit", "")
414        CS_appendMetaData(fileID, preMeta + "/beam/size/y",                preXpath + "/cs:beam_size/cs:y", "")
415        CS_appendMetaData(fileID, preMeta + "/beam/size/y@unit",           preXpath + "/cs:beam_size/cs:y/@unit", "")
416        CS_appendMetaData(fileID, preMeta + "/beam/size/z",                preXpath + "/cs:beam_size/cs:z", "")
417        CS_appendMetaData(fileID, preMeta + "/beam/size/z@unit",           preXpath + "/cs:beam_size/cs:z/@unit", "")
418        CS_appendMetaData(fileID, preMeta + "/beam/shape",                 preXpath + "/cs:beam_shape", "")
419        CS_appendMetaData(fileID, preMeta + "/wavelength",                 preXpath + "/cs:wavelength", "")
420        CS_appendMetaData(fileID, preMeta + "/wavelength/@unit",           preXpath + "/cs:wavelength/@unit", "")
421        CS_appendMetaData(fileID, preMeta + "/wavelength_min",             preXpath + "/cs:wavelength_min", "")
422        CS_appendMetaData(fileID, preMeta + "/wavelength_min/@unit",       preXpath + "/cs:wavelength_min/@unit", "")
423        CS_appendMetaData(fileID, preMeta + "/wavelength_max",             preXpath + "/cs:wavelength_max", "")
424        CS_appendMetaData(fileID, preMeta + "/wavelength_max/@unit",       preXpath + "/cs:wavelength_max/@unit", "")
425        CS_appendMetaData(fileID, preMeta + "/wavelength_spread",          preXpath + "/cs:wavelength_spread", "")
426        CS_appendMetaData(fileID, preMeta + "/wavelength_spread/@unit",    preXpath + "/cs:wavelength_spread/@unit", "")
427
428        // <SASinstrument><SAScollimation> might appear multiple times
429        XmlListXpath(fileID, sasEntryPath+"/cs:SASinstrument//cs:SAScollimation", nsStr)        //output: M_listXPath
430        WAVE/T  M_listXPath
431        DUPLICATE/O/T   M_listXPath, SAScollimationList
432        STRING collimationPath
433        FOR (i = 0; i < DimSize(SAScollimationList, 0); i += 1)
434                preMeta = "SASinstrument/SAScollimation"
435                IF (DimSize(SAScollimationList, 0) > 1)
436                        preMeta += "_" + num2str(i)
437                ENDIF
438                collimationPath = sasEntryPath+"/cs:SASinstrument/cs:SAScollimation["+num2str(i+1)+"]"
439                CS_appendMetaData(fileID, preMeta + "/@name",               collimationPath + "/@name", "")
440                CS_appendMetaData(fileID, preMeta + "/length",              collimationPath + "/cs:length", "")
441                CS_appendMetaData(fileID, preMeta + "/length_unit",         collimationPath + "/cs:length/@unit", "")
442                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)        // aperture may be repeated!
443                        IF (DimSize(M_listXPath, 0) == 1)
444                                preMeta = "SASinstrument/SAScollimation/aperture"
445                        ELSE
446                                preMeta = "SASinstrument/SAScollimation/aperture_" + num2str(j)
447                        ENDIF
448                        preXpath = collimationPath + "/cs:aperture["+num2str(j+1)+"]"
449                        CS_appendMetaData(fileID, preMeta + "/@name",         preXpath + "/@name", "")
450                        CS_appendMetaData(fileID, preMeta + "/type",          preXpath + "/cs:type", "")
451                        CS_appendMetaData(fileID, preMeta + "/size/@name",     preXpath + "/cs:size/@name", "")
452                        CS_appendMetaData(fileID, preMeta + "/size/x",        preXpath + "/cs:size/cs:x", "")
453                        CS_appendMetaData(fileID, preMeta + "/size/x/@unit",   preXpath + "/cs:size/cs:x/@unit", "")
454                        CS_appendMetaData(fileID, preMeta + "/size/y",        preXpath + "/cs:size/cs:y", "")
455                        CS_appendMetaData(fileID, preMeta + "/size/y/@unit",   preXpath + "/cs:size/cs:y/@unit", "")
456                        CS_appendMetaData(fileID, preMeta + "/size/z",        preXpath + "/cs:size/cs:z", "")
457                        CS_appendMetaData(fileID, preMeta + "/size/z/@unit",   preXpath + "/cs:size/cs:z/@unit", "")
458                        CS_appendMetaData(fileID, preMeta + "/distance",       preXpath + "/cs:distance", "")
459                        CS_appendMetaData(fileID, preMeta + "/distance/@unit", preXpath + "/cs:distance/@unit", "")
460                ENDFOR
461        ENDFOR
462
463        // <SASinstrument><SASdetector> might appear multiple times
464        XmlListXpath(fileID, sasEntryPath+"/cs:SASinstrument//cs:SASdetector", nsStr)   //output: M_listXPath
465        WAVE/T  M_listXPath
466        DUPLICATE/O/T   M_listXPath, SASdetectorList
467        FOR (i = 0; i < DimSize(SASdetectorList, 0); i += 1)
468                preMeta = "SASinstrument/SASdetector"
469                IF (DimSize(SASdetectorList, 0) > 1)
470                        preMeta += "_" + num2str(i)
471                ENDIF
472                detectorPath = sasEntryPath+"/cs:SASinstrument/cs:SASdetector["+num2str(i+1)+"]"
473                CS_appendMetaData(fileID, preMeta + "/@name",                    detectorPath + "/cs:name", "")
474                CS_appendMetaData(fileID, preMeta + "/SDD",                              detectorPath + "/cs:SDD", "")
475                CS_appendMetaData(fileID, preMeta + "/SDD/@unit",                        detectorPath + "/cs:SDD/@unit", "")
476                CS_appendMetaData(fileID, preMeta + "/offset/@name",             detectorPath + "/cs:offset/@name", "")
477                CS_appendMetaData(fileID, preMeta + "/offset/x",                 detectorPath + "/cs:offset/cs:x", "")
478                CS_appendMetaData(fileID, preMeta + "/offset/x/@unit",           detectorPath + "/cs:offset/cs:x/@unit", "")
479                CS_appendMetaData(fileID, preMeta + "/offset/y",                 detectorPath + "/cs:offset/cs:y", "")
480                CS_appendMetaData(fileID, preMeta + "/offset/y/@unit",           detectorPath + "/cs:offset/cs:y/@unit", "")
481                CS_appendMetaData(fileID, preMeta + "/offset/z",                 detectorPath + "/cs:offset/cs:z", "")
482                CS_appendMetaData(fileID, preMeta + "/offset/z/@unit",           detectorPath + "/cs:offset/cs:z/@unit", "")
483
484                CS_appendMetaData(fileID, preMeta + "/orientation/@name",        detectorPath + "/cs:orientation/@name", "")
485                CS_appendMetaData(fileID, preMeta + "/orientation/roll",         detectorPath + "/cs:orientation/cs:roll", "")
486                CS_appendMetaData(fileID, preMeta + "/orientation/roll/@unit",   detectorPath + "/cs:orientation/cs:roll/@unit", "")
487                CS_appendMetaData(fileID, preMeta + "/orientation/pitch",        detectorPath + "/cs:orientation/cs:pitch", "")
488                CS_appendMetaData(fileID, preMeta + "/orientation/pitch/@unit",   detectorPath + "/cs:orientation/cs:pitch/@unit", "")
489                CS_appendMetaData(fileID, preMeta + "/orientation/yaw",          detectorPath + "/cs:orientation/cs:yaw", "")
490                CS_appendMetaData(fileID, preMeta + "/orientation/yaw/@unit",    detectorPath + "/cs:orientation/cs:yaw/@unit", "")
491
492                CS_appendMetaData(fileID, preMeta + "/beam_center/@name",        detectorPath + "/cs:beam_center/@name", "")
493                CS_appendMetaData(fileID, preMeta + "/beam_center/x",            detectorPath + "/cs:beam_center/cs:x", "")
494                CS_appendMetaData(fileID, preMeta + "/beam_center/x/@unit",      detectorPath + "/cs:beam_center/cs:x/@unit", "")
495                CS_appendMetaData(fileID, preMeta + "/beam_center/y",            detectorPath + "/cs:beam_center/cs:y", "")
496                CS_appendMetaData(fileID, preMeta + "/beam_center/y/@unit",      detectorPath + "/cs:beam_center/cs:y/@unit", "")
497                CS_appendMetaData(fileID, preMeta + "/beam_center/z",            detectorPath + "/cs:beam_center/cs:z", "")
498                CS_appendMetaData(fileID, preMeta + "/beam_center/z/@unit",      detectorPath + "/cs:beam_center/cs:z/@unit", "")
499
500                CS_appendMetaData(fileID, preMeta + "/pixel_size/@name",         detectorPath + "/cs:pixel_size/@name", "")
501                CS_appendMetaData(fileID, preMeta + "/pixel_size/x",             detectorPath + "/cs:pixel_size/cs:x", "")
502                CS_appendMetaData(fileID, preMeta + "/pixel_size/x/@unit",       detectorPath + "/cs:pixel_size/cs:x/@unit", "")
503                CS_appendMetaData(fileID, preMeta + "/pixel_size/y",             detectorPath + "/cs:pixel_size/cs:y", "")
504                CS_appendMetaData(fileID, preMeta + "/pixel_size/y/@unit",       detectorPath + "/cs:pixel_size/cs:y/@unit", "")
505                CS_appendMetaData(fileID, preMeta + "/pixel_size/z",             detectorPath + "/cs:pixel_size/cs:z", "")
506                CS_appendMetaData(fileID, preMeta + "/pixel_size/z/@unit",       detectorPath + "/cs:pixel_size/cs:z/@unit", "")
507
508                CS_appendMetaData(fileID, preMeta + "/slit_length",                    detectorPath + "/cs:slit_length", "")
509                CS_appendMetaData(fileID, preMeta + "/slit_length/@unit",              detectorPath + "/cs:slit_length/@unit", "")
510        ENDFOR
511
512        // <SASprocess> might appear multiple times
513        XmlListXpath(fileID, sasEntryPath+"//cs:SASprocess", nsStr)     //output: M_listXPath
514        WAVE/T  M_listXPath
515        DUPLICATE/O/T   M_listXPath, SASprocessList
516        STRING SASprocessPath, prefix
517        FOR (i = 0; i < DimSize(SASprocessList, 0); i += 1)
518                preMeta = "SASprocess"
519                IF (DimSize(SASprocessList, 0) > 1)
520                        preMeta += "_" + num2str(i)
521                ENDIF
522                SASprocessPath = sasEntryPath+"/cs:SASprocess["+num2str(i+1)+"]"
523                CS_appendMetaData(fileID, preMeta+"/@name",        SASprocessPath + "/@name", "")
524                CS_appendMetaData(fileID, preMeta+"/name",         SASprocessPath + "/cs:name", "")
525                CS_appendMetaData(fileID, preMeta+"/date",                 SASprocessPath + "/cs:date", "")
526                CS_appendMetaData(fileID, preMeta+"/description",   SASprocessPath + "/cs:description", "")
527                XmlListXpath(fileID, SASprocessPath+"//cs:term", nsStr)
528                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)
529                        prefix = SASprocessPath + "/cs:term[" + num2str(j+1) + "]"
530                        CS_appendMetaData(fileID, preMeta+"/term_"+num2str(j)+"/@name",     prefix + "/@name", "")
531                        CS_appendMetaData(fileID, preMeta+"/term_"+num2str(j)+"/@unit",           prefix + "/@unit", "")
532                        CS_appendMetaData(fileID, preMeta+"/term_"+num2str(j),                            prefix, "")
533                ENDFOR
534                // ignore <SASprocessnote>
535        ENDFOR
536
537        // <SASnote> might appear multiple times
538        XmlListXpath(fileID, sasEntryPath+"//cs:SASnote", nsStr)        //output: M_listXPath
539        WAVE/T  M_listXPath
540        DUPLICATE/O/T   M_listXPath, SASnoteList
541        FOR (i = 0; i < DimSize(SASnoteList, 0); i += 1)
542                preMeta = "SASnote"
543                IF (DimSize(SASnoteList, 0) > 1)
544                        preMeta += "_" + num2str(i)
545                ENDIF
546                notePath = sasEntryPath+"//cs:SASnote["+num2str(i+1)+"]"
547                CS_appendMetaData(fileID, preMeta+"/@name",     notePath + "/@name", "")
548                CS_appendMetaData(fileID, preMeta,              notePath, "")
549        ENDFOR
550
551        KillWaves/Z M_listXPath, detailsList, SAScollimationList, SASdetectorList, SASprocessList, SASnoteList
552END
553
554// ==================================================================
555
556FUNCTION/S CS_1i_locateTitle(fileID, SASentryPath)
557        VARIABLE fileID
558        STRING SASentryPath
559        STRING TitlePath, Title
560        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
561        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
562
563        // /cs:SASroot/cs:SASentry/cs:Title is the expected location, but it could be empty
564        TitlePath = SASentryPath + "/cs:Title"
565        Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
566        // search harder for a title
567        IF (strlen(Title) == 0)
568                TitlePath = SASentryPath + "/@name"
569                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
570        ENDIF
571        IF (strlen(Title) == 0)
572                TitlePath = SASentryPath + "/cs:SASsample/cs:ID"
573                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
574        ENDIF
575        IF (strlen(Title) == 0)
576                TitlePath = SASentryPath + "/cs:SASsample/@name"
577                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
578        ENDIF
579        IF (strlen(Title) == 0)
580                // last resort: make up a title
581                Title = "SASentry"
582                TitlePath = ""
583        ENDIF
584        PRINT "\t Title:", Title
585        RETURN(Title)
586END
587
588// ==================================================================
589
590FUNCTION CS_appendMetaData(fileID, key, xpath, value)
591        VARIABLE fileID
592        STRING key, xpath, value
593        WAVE/T metadata
594        STRING k, v
595
596        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
597        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
598
599        k = TrimWS(key)
600        IF (  strlen(k) > 0 )
601                IF ( strlen(xpath) > 0 )
602                        value = XMLstrFmXpath(fileID,  xpath, nsStr, "")
603                ENDIF
604                // What if the value string has a ";" embedded?
605                //  This could complicate (?compromise?) the wavenote "key=value;" syntax.
606                //  But let the caller deal with it.
607                v = TrimWS(ReplaceString(";", value, " :semicolon: "))
608                IF ( strlen(v) > 0 )
609                        VARIABLE last
610                        last = DimSize(metadata, 0)
611                        Redimension/N=(last+1, 2) metadata
612                        metadata[last][0] = k
613                        metadata[last][1] = v
614                ENDIF
615        ENDIF
616END
617
618// ==================================================================
619
620Function/T   TrimWS(str)
621    // TrimWhiteSpace (code from Jon Tischler)
622    String str
623    return TrimWSL(TrimWSR(str))
624End
625
626// ==================================================================
627
628Function/T   TrimWSL(str)
629    // TrimWhiteSpaceLeft (code from Jon Tischler)
630    String str
631    Variable i, N=strlen(str)
632    for (i=0;char2num(str[i])<=32 && i<N;i+=1)    // find first non-white space
633    endfor
634    return str[i,Inf]
635End
636
637// ==================================================================
638
639Function/T   TrimWSR(str)
640    // TrimWhiteSpaceRight (code from Jon Tischler)
641    String str
642    Variable i
643    for (i=strlen(str)-1; char2num(str[i])<=32 && i>=0; i-=1)    // find last non-white space
644    endfor
645    return str[0,i]
646End
647
648// ==================================================================
649// ==================================================================
650// ==================================================================
651
652
653FUNCTION prj_grabMyXmlData()
654        STRING srcDir = "root:Packages:CS_XMLreader"
655        STRING destDir = "root:PRJ_canSAS"
656        STRING srcFolder, destFolder, theFolder
657        Variable i
658        NewDataFolder/O  $destDir               // for all my imported data
659        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 )
660                theFolder = GetIndexedObjName(srcDir, 4, i)
661                srcFolder = srcDir + ":" + theFolder
662                destFolder = destDir + ":" + theFolder
663                // PRINT srcFolder, destFolder
664                IF (DataFolderExists(destFolder))
665                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
666                        // need to find unique name for destination
667                        // Persons who implement this properly should be more elegant
668                        // For now, I will blast the existing and proceed blindly.
669                        KillDataFolder/Z  $destFolder           // clear out any previous work
670                        DuplicateDataFolder $srcFolder, $destFolder
671                ELSE
672                        DuplicateDataFolder $srcFolder, $destFolder
673                ENDIF
674        ENDFOR
675END
676
677FUNCTION prjTest_cansas1d()
678        // unit tests for the routines under prj-readXML.ipf
679        STRING theFile
680        STRING fList = ""
681        VARIABLE i, result, timerID, seconds
682        // build a table of test data sets
683        fList = AddListItem("elmo.xml",                                 fList, ";", Inf)                // non-existent file
684        fList = AddListItem("cansasXML.ipf",                    fList, ";", Inf)                // this file (should fail on XML parsing)
685        fList = AddListItem("book.xml",                                 fList, ";", Inf)                // good XML example file but not canSAS, not even close
686        fList = AddListItem("bimodal-test1.xml",                fList, ";", Inf)                // simple dataset
687        fList = AddListItem("bimodal-test2-vector.xml", fList, ";", Inf)                // version 2.0 file (no standard yet)
688        fList = AddListItem("test.xml",                                 fList, ";", Inf)                // cs_collagen.xml with no namespace
689        fList = AddListItem("test2.xml",                                fList, ";", Inf)                // version 2.0 file (no standard yet)
690        fList = AddListItem("ISIS_SANS_Example.xml",    fList, ";", Inf)                // from S. King, 2008-03-17
691        fList = AddListItem("W1W2.xml",                                 fList, ";", Inf)                // from S. King, 2008-03-17
692        fList = AddListItem("ill_sasxml_example.xml",   fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
693        fList = AddListItem("isis_sasxml_example.xml",  fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
694        fList = AddListItem("r586.xml",                                         fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
695        fList = AddListItem("r597.xml",                                         fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
696        fList = AddListItem("xg009036_001.xml",                 fList, ";", Inf)                // foreign elements with other namespaces
697        fList = AddListItem("cs_collagen.xml",                  fList, ";", Inf)                // another simple dataset, bare minimum info
698        fList = AddListItem("cs_collagen_full.xml",             fList, ";", Inf)                // more Q range than previous
699        fList = AddListItem("cs_af1410.xml",                    fList, ";", Inf)                // multiple SASentry and SASdata elements
700        fList = AddListItem("cansas1d-template.xml",    fList, ";", Inf)                // multiple SASentry and SASdata elements
701        fList = AddListItem("1998spheres.xml",                  fList, ";", Inf)                // 2 SASentry, few thousand data points each
702        fList = AddListItem("does-not-exist-file.xml",          fList, ";", Inf)                // non-existent file
703        fList = AddListItem("cs_rr_polymers.xml",               fList, ";", Inf)                // Round Robin polymer samples from John Barnes @ NIST
704        fList = AddListItem("s81-polyurea.xml",                         fList, ";", Inf)                // polyurea from APS/USAXS/Indra (with extra metadata)
705       
706        // try to load each data set in the table
707        FOR ( i = 0; i < ItemsInList(fList) ; i += 1 )
708                theFile = StringFromList(i, fList)                                      // walk through all test files
709                // PRINT "file: ", theFile
710                pathInfo home
711                //IF (CS_XmlReader(theFile) == 0)                                       // did the XML reader return without an error code?
712                timerID = StartMStimer
713                result = CS_XmlReader(ParseFilePath(5,S_path,"*",0,0) + theFile)
714                seconds = StopMSTimer(timerID) * 1.0e-6
715                PRINT "\t Completed in ", seconds, " seconds"
716                IF (result == 0)    // did the XML reader return without an error code?
717                        prj_grabMyXmlData()                                             // move the data to my directory
718                ENDIF
719        ENDFOR
720END
721
722
723FUNCTION testCollette()
724                                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
725                                        //          THIS IS JUST AN EXAMPLE
726
727// suggestions from ISIS users
728        // 3.   Loading actual data from LOQ caused some problems.
729        //      Data created by Colette names files with run number.
730        //      When entering full path to load the data if you use "…\example\31531.X" Igor will read \3 as a character.
731        //      A simple fix which has worked for this is to use / instead of \ e.g. "…\example/31531.X".
732       
733        //4.    Once data is loaded in Igor it is relatively easy to work with but would be nicer if the SASdata
734        //      was loaded into root directory (named using run number rather than generically as it is at the moment) rather than another folder.
735        //This becomes more problematic when two samples are being loaded for comparison.
736        //      Although still relatively easy to work with, changing the folders can lead to mistakes being made.
737
738        //Say, for Run=31531, then Qsas_31531
739
740        CS_XmlReader("W1W2.XML")
741        STRING srcDir = "root:Packages:CS_XMLreader"
742        STRING destDir = "root", importFolder, target
743        Variable i, j
744        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 )
745                SetDataFolder $srcDir
746                importFolder = GetIndexedObjName(srcDir, 4, i)
747                SetDataFolder $importFolder
748                IF ( EXISTS( "metadata" ) == 1 )
749                        // looks like a SAS data folder
750                        WAVE/T metadata
751                        STRING Run = ""
752                        FOR (j = 0; j < DimSize(metadata, 0); j += 1)
753                                IF ( CmpStr( "Run", metadata[j][0]) == 0 )
754                                        // get the Run number and "clean" it up a bit
755                                        Run = TrimWS(  ReplaceString("\\", metadata[j][1], "/")  )
756                                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
757                                        // need to find unique name for destination waves       
758                                        //          THIS IS JUST AN EXAMPLE
759                                        // Persons who implement this properly should be more elegant
760                                        // For now, I will blast any existing and proceed blindly.
761                                        target = "root:Qsas_" + Run
762                                        Duplicate/O Qsas, $target
763                                        target = "root:Isas_" + Run
764                                        Duplicate/O Isas, $target
765                                        IF ( exists( "Idev" ) == 1 )
766                                                target = "root:Idev_" + Run
767                                                Duplicate/O Idev, $target
768                                        ENDIF
769                                        IF ( exists( "Qdev" ) == 1 )
770                                                target = "root:Qdev_" + Run
771                                                Duplicate/O Qdev, $target
772                                        ENDIF
773                                        IF ( exists( "dQw" ) == 1 )
774                                                target = "root:QdQw_" + Run
775                                                Duplicate/O dQw, $target
776                                        ENDIF
777                                        IF ( exists( "dQl" ) == 1 )
778                                                target = "root:dQl_" + Run
779                                                Duplicate/O dQl, $target
780                                        ENDIF
781                                        IF ( exists( "Qmean" ) == 1 )
782                                                target = "root:Qmean_" + Run
783                                                Duplicate/O Qmean, $target
784                                        ENDIF
785                                        IF ( exists( "Shadowfactor" ) == 1 )
786                                                target = "root:Shadowfactor_" + Run
787                                                Duplicate/O Shadowfactor, $target
788                                        ENDIF
789                                        target = "root:metadata_" + Run
790                                        Duplicate/O/T metadata, $target
791                                        BREAK
792                                ENDIF
793                        ENDFOR
794                ENDIF
795        ENDFOR
796
797        SetDataFolder root:
798END
Note: See TracBrowser for help on using the repository browser.