source: sans/Dev/trunk/NCNR_User_Procedures/Common/cansasXML_v11.ipf @ 481

Last change on this file since 481 was 481, checked in by ajj, 14 years ago

Sundry changes...

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