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

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

use trunk,tags,branches

File size: 25.1 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2
3# file: cansasXML.ipf
4# author:       Pete R. Jemian <jemian@anl.gov>
5# date: 2008-03-07
6# purpose:  implement an IgorPro file reader to read the canSAS 1-D reduced SAS data in XML files
7#                       adheres to the cansas1d/1.0 standard
8# URL:  http://www.smallangles.net/wgwiki/index.php/cansas1d_documentation
9
10FUNCTION CS_XmlReader(fileName)
11        //
12        // open a canSAS 1-D reduced SAS XML data file
13        //      returns:
14        //              0 : successful
15        //              -1: XML file not found
16        //              -2: root element is not <SASroot>
17        //              -3: <SASroot> version  is not 1.0
18        //              -4: no <SASentry> elements
19        //
20        STRING fileName
21        STRING origFolder
22        STRING workingFolder = "root:Packages:CS_XMLreader"
23        VARIABLE returnCode
24
25        //
26        // set up a work folder within root:Packages
27        // Clear out any progress/results from previous activities
28        //
29        origFolder = GetDataFolder(1)
30        SetDataFolder root:                                     // start in the root data folder
31        NewDataFolder/O  root:Packages          // good practice
32        KillDataFolder/Z  $workingFolder                // clear out any previous work
33        NewDataFolder/O/S  $workingFolder       // Do all our work in root:XMLreader
34
35        //
36        // Try to open the named XML file (clean-up and return if failure)
37        //
38        VARIABLE fileID
39        STRING/G errorMsg, xmlFile
40        MAKE/T/N=(0,3)/O metadata
41        CS_appendMetaData("xmlFile", "", fileName)
42        xmlFile = fileName
43        IF ( CS_fileExists(fileName) == 0 )
44                errorMsg = fileName + ": XML file not found"
45                PRINT errorMsg
46                SetDataFolder $origFolder
47                RETURN(-1)                                              // could not find file
48        ENDIF
49        fileID = XmlOpenFile(fileName)                  // open and parse the XMLfile
50        IF ( fileID < 0 )
51                errorMsg = fileName + ": XML file not found"
52                PRINT errorMsg
53                SetDataFolder $origFolder
54                RETURN(-1)                                              // could not find file
55        ENDIF
56
57        //
58        // index the XML element list
59        //
60        XmlElemList(fileID)                                     // load the elementlist into W_ElementList
61        WAVE/T  W_ElementList                           // This declaration comes _after_ XmlElemList() is called
62        CS_registerNameSpaces()                         // to assist XPath construction
63
64        // assume for now that canSAS namespace is constant throughout this XML
65        // call this code once here, rather many times throughout
66        STRING/G nsPre = "", nsStr = ""
67        nsPre = CS_GetKeyByNameSpace(W_ElementList[0][1])
68        IF (strlen(nsPre) > 0)
69                nsStr = nsPre + "=" + W_ElementList[0][1]
70                nsPre += ":"
71        ENDIF
72
73        // qualify the XML file, don't allow just any ole XML.
74        IF ( CmpStr(W_ElementList[0][3], "SASroot") != 0 )              // deftly avoid namespace
75                errorMsg = fileName + ": root element is not <SASroot>"
76                PRINT errorMsg
77                XmlCloseFile(fileID,0)
78                SetDataFolder $origFolder
79                RETURN(-2)                                              // not a canSAS XML file
80        ENDIF
81        // identify supported versions of canSAS XML standard
82        STRING version
83        version = StringByKey("version", W_ElementList[0][2])
84        CS_appendMetaData("cansas_version", CS_XPath_NS("/SASroot/@version"), version)
85        STRSWITCH(version)     
86        CASE "1.0":                                                     // version 1.0 of the canSAS 1-D reduced SAS data standard
87                PRINT fileName, " identified as: cansas1d/1.0 XML file"
88                returnCode = CS_1i_parseXml(fileID)
89                IF (returnCode != 0)
90                        IF (strlen(errorMsg) == 0)
91                                errorMsg = "error while parsing the XML"
92                        ENDIF
93                        PRINT errorMsg
94                        XmlCloseFile(fileID,0)
95                        SetDataFolder $origFolder
96                        RETURN(returnCode)                      // error while parsing the XML
97                ENDIF
98                BREAK
99        CASE "2.0a":                                            // unsupported
100        DEFAULT:                                                        // optional default expression executed
101                errorMsg = fileName + ": <SASroot> version (" + version + ") is not supported"
102                PRINT errorMsg
103                XmlCloseFile(fileID,0)
104                SetDataFolder $origFolder
105                RETURN(-3)                                              // attribute list must include version="1.0"
106        ENDSWITCH
107
108        XmlCloseFile(fileID,0)                                  // now close the file, without saving
109        fileID = -1
110
111        SetDataFolder $origFolder
112        RETURN(0)                                                       // execution finished OK
113END
114
115// ==================================================================
116
117FUNCTION CS_1i_parseXml(fileID)
118        VARIABLE fileID
119        WAVE/T W_ElementList
120        SVAR nsStr, errorMsg
121        STRING/G Title, FolderList = ""
122        STRING XPathStr, Title_folder, SASdata_folder
123        VARIABLE i, j, index, SASdata_index
124
125        // locate all the SASentry elements
126        CS_simpleXmlListXpath(fileID, "", "/SASroot//SASentry")
127        WAVE/T  W_listXPath
128        DUPLICATE/O/T   W_listXPath, SASentryList
129
130        IF (numpnts(SASentryList) < 1)
131                errorMsg = "could not find any SASentry elements in XML file"
132                PRINT errorMsg
133                RETURN(-4)                                              // no <SASentry> elements
134        ENDIF
135
136        //
137        // process each SASentry element
138        // (safer to copy W_listxpath to a local variable and allow for other calls to XMLlistXpath)
139        DUPLICATE/O/T metadata, metadata_file
140        FOR (i = 0; i < numpnts(SASentryList); i += 1)
141                index = CS_findElementIndex(SASentryList[i])
142                // Get each /SASentry/Title to create a data folder
143                Title = CS_XmlStrFmXpath(fileID, SASentryList[i], "/Title")
144                PRINT "\t Title:", Title
145                DUPLICATE/O/T metadata_file, metadata
146                CS_appendMetaData("title", SASentryList[i]+CS_XPath_NS("/Title"), Title)
147                Title_folder = CleanupName(Title, 0)
148                IF ( CheckName(Title_folder, 11) != 0 )
149                        Title_folder = UniqueName(Title_folder, 11, 0)
150                ENDIF
151                NewDataFolder/O  $Title_folder
152                FolderList = AddListItem(Title_folder, FolderList, ";", Inf)
153                //
154                CS_1i_collectMetadata(fileID, SASentryList[i])
155                //
156                // next, extract each SASdata block into a subfolder
157                CS_simpleXmlListXpath(fileID, SASentryList[i], "//SASdata")     //output: W_listXPath
158                DUPLICATE/O/T   W_listXPath, SASdataList
159                IF (numpnts(SASdataList) == 1)
160                        // only one SASdata element, place data waves in Title folder
161                        SASdata_folder = ":" + Title_folder + ":"
162                        PRINT "\t\t dataFolder:", SASdata_folder
163                        CS_1i_extractSasData(fileID, SASdataList[0], SASdata_folder)
164                        CS_appendMetaData(  "Run", "", CS_XmlStrFmXpath(fileID, SASdataList[0]+"/",  "../Run["+num2str(j+1)+"]"))
165                        CS_appendMetaData(  "Run_name", "", CS_XmlStrFmXpath(fileID, SASdataList[0]+"/",  "../Run["+num2str(j+1)+"]/@name"))
166                        CS_appendMetaData(  "SASdata_name", "", CS_XmlStrFmXpath(fileID, SASdataList[0],  "/@name"))
167                ELSE
168                        // multiple SASdata elements, place data waves in subfolders
169                        DUPLICATE/O/T metadata, metadata_entry
170                        FOR (j = 0; j < numpnts(SASdataList); j += 1)
171                                DUPLICATE/O/T metadata_entry, metadata
172                                XMLlistAttr(fileID,SASdataList[j],nsStr)
173                                WAVE/T M_ListAttr
174                                SASdata_index = CS_findElementIndex(SASdataList[j])
175                                SASdata_folder = CleanupName(StringByKey("name", W_ElementList[SASdata_index][2]), 0)
176                                PRINT "\t\t dataFolder:", SASdata_folder
177                                CS_appendMetaData(  "Run"+num2str(j), "", CS_XmlStrFmXpath(fileID, SASdataList[j]+"/",  "../Run["+num2str(j+1)+"]"))
178                                CS_appendMetaData(  "Run"+num2str(j)+"_name", "", CS_XmlStrFmXpath(fileID, SASdataList[j]+"/",  "../Run["+num2str(j+1)+"]/@name"))
179                                CS_appendMetaData(  "SASdata"+num2str(j)+"_name", "", CS_XmlStrFmXpath(fileID, SASdataList[j],  "/@name"))
180                                SetDataFolder $Title_folder
181                                IF ( CheckName(SASdata_folder, 11) != 0 )
182                                        SASdata_folder = UniqueName(SASdata_folder, 11, 0)
183                                ENDIF
184                                NewDataFolder/O  $SASdata_folder
185                                SetDataFolder ::
186                                SASdata_folder =  ":" + Title_folder + ":" + SASdata_folder + ":"
187                                //---
188                                CS_1i_extractSasData(fileID, SASdataList[j], SASdata_folder)
189                        ENDFOR
190                ENDIF
191        ENDFOR
192
193        RETURN(0)
194END
195
196// ==================================================================
197
198FUNCTION CS_1i_collectMetadata(fileID, sasEntryPath)
199        VARIABLE fileID
200        STRING sasEntryPath
201        SVAR nsStr
202        VARIABLE i
203        WAVE/T metadata
204        STRING suffix = ""
205        STRING value
206        // collect some metadata
207        // first, fill a table with keywords, and XPath locations, 3rd column will be values
208
209        // handle most <SASsample> fields
210        CS_appendMetaData("sample_ID",                                          sasEntryPath+CS_XPath_NS("/SASsample/ID"), "")
211        CS_appendMetaData("sample_thickness",                           sasEntryPath+CS_XPath_NS("/SASsample/thickness"), "")
212        CS_appendMetaData("sample_thickness_unit",                      sasEntryPath+CS_XPath_NS("/SASsample/thickness/@unit"), "")
213        CS_appendMetaData("sample_transmission",                        sasEntryPath+CS_XPath_NS("/SASsample/transmission"), "")
214        CS_appendMetaData("sample_temperature",                         sasEntryPath+CS_XPath_NS("/SASsample/temperature"), "")
215        CS_appendMetaData("sample_temperature_unit",            sasEntryPath+CS_XPath_NS("/SASsample/temperature/@unit"), "")
216        CS_appendMetaData("sample_position_x",                          sasEntryPath+CS_XPath_NS("/SASsample/position/x"), "")
217        CS_appendMetaData("sample_position_x_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/x/@unit"), "")
218        CS_appendMetaData("sample_position_y",                          sasEntryPath+CS_XPath_NS("/SASsample/position/y"), "")
219        CS_appendMetaData("sample_position_y_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/y/@unit"), "")
220        CS_appendMetaData("sample_position_z",                          sasEntryPath+CS_XPath_NS("/SASsample/position/z"), "")
221        CS_appendMetaData("sample_position_z_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/z/@unit"), "")
222        CS_appendMetaData("sample_orientation_roll",                    sasEntryPath+CS_XPath_NS("/SASsample/orientation/roll"), "")
223        CS_appendMetaData("sample_orientation_roll_unit",               sasEntryPath+CS_XPath_NS("/SASsample/orientation/roll/@unit"), "")
224        CS_appendMetaData("sample_orientation_pitch",           sasEntryPath+CS_XPath_NS("/SASsample/orientation/pitch"), "")
225        CS_appendMetaData("sample_orientation_pitch_unit",      sasEntryPath+CS_XPath_NS("/SASsample/orientation/pitch/@unit"), "")
226        CS_appendMetaData("sample_orientation_yaw",                     sasEntryPath+CS_XPath_NS("/SASsample/orientation/yaw"), "")
227        CS_appendMetaData("sample_orientation_yaw_unit",        sasEntryPath+CS_XPath_NS("/SASsample/orientation/yaw/@unit"), "")
228        // <SASsample><details> might appear multiple times, too!
229        CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASsample//details")      //output: W_listXPath
230        DUPLICATE/O/T   W_listXPath, detailsList
231        suffix = ""
232        FOR (i = 0; i < numpnts(detailsList); i += 1)
233                IF (numpnts(detailsList) > 1)
234                        suffix = num2str(i)
235                ENDIF
236                CS_appendMetaData("sample_details"+suffix+"_name",      detailsList[i]+CS_XPath_NS("/@name"), "")
237                CS_appendMetaData("sample_details"+suffix,                      detailsList[i], "")
238        ENDFOR
239
240
241        // <SASinstrument>
242        CS_appendMetaData("Instrument_name", sasEntryPath+CS_XPath_NS("/SASinstrument/name"), "")
243
244        // <SASinstrument><SASsource>
245        CS_appendMetaData("source_name", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/@name"), "")
246        CS_appendMetaData("radiation", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/radiation"), "")
247        CS_appendMetaData("beam_shape", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_shape"), "")
248        // ignore <beam_size> for now
249        CS_appendMetaData("wavelength", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength"), "")
250        CS_appendMetaData("wavelength_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength/@unit"), "")
251        CS_appendMetaData("wavelength_min", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_min"), "")
252        CS_appendMetaData("wavelength_min_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_min/@unit"), "")
253        CS_appendMetaData("wavelength_max", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_max"), "")
254        CS_appendMetaData("wavelength_max_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_max/@unit"), "")
255        CS_appendMetaData("wavelength_spread", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_spread"), "")
256        CS_appendMetaData("wavelength_spread_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_spread/@unit"), "")
257
258        // ignore <SASinstrument><SAScollimation> for now
259
260        // <SASinstrument><SASdetector> might appear multiple times
261        CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASinstrument//SASdetector")      //output: W_listXPath
262        DUPLICATE/O/T   W_listXPath, SASdetectorList
263        suffix = ""
264        FOR (i = 0; i < numpnts(SASdetectorList); i += 1)
265                IF (numpnts(SASdetectorList) > 1)
266                        suffix = num2str(i)
267                ENDIF
268                CS_appendMetaData("detector_name"+suffix,       SASdetectorList[i]+CS_XPath_NS("/name"), "")
269                CS_appendMetaData("SDD"+suffix,                         SASdetectorList[i]+CS_XPath_NS("/SDD"), "")
270                CS_appendMetaData("SDD"+suffix+"_unit",                 SASdetectorList[i]+CS_XPath_NS("/SDD/@unit"), "")
271                // ignore <offset> for now
272                // ignore <orientation> for now
273                // ignore <beam_center> for now
274                // ignore <pixel_size> for now
275                CS_appendMetaData("slit_length"+suffix,                 SASdetectorList[i]+CS_XPath_NS("/slit_length"), "")
276                CS_appendMetaData("slitLength"+suffix+"_unit",  SASdetectorList[i]+CS_XPath_NS("/slit_length/@unit"), "")
277        ENDFOR
278
279        // ignore <SASprocess> for now
280
281        // <SASnote> might appear multiple times
282        CS_simpleXmlListXpath(fileID, sasEntryPath, "//SASnote")        //output: W_listXPath
283        DUPLICATE/O/T   W_listXPath, SASnoteList
284        suffix = ""
285        FOR (i = 0; i < numpnts(SASnoteList); i += 1)
286                IF (numpnts(SASnoteList) > 1)
287                        suffix = num2str(i)
288                ENDIF
289                CS_appendMetaData("SASnote"+suffix+"_name",     SASnoteList[i]+CS_XPath_NS("/@name"), "")
290                CS_appendMetaData("SASnote"+suffix,                             SASnoteList[i], "")
291        ENDFOR
292
293        // +++++++++++++++++++++++++                    // try to fill the value column from the XML data
294        FOR (i = 0; i < DimSize(metadata, 0); i += 1)
295                IF (strlen(metadata[i][1]) > 0)                         // XPathStr for this entry?
296                        IF (strlen(metadata[i][2])  == 0)                       // not defined yet?
297                                value = CS_XmlStrFmXpath(fileID, metadata[i][1], "")            // get it
298                                // What if the value string has a ";" embedded?
299                                //  This will complicate (?compromise?) the wavenote "key=value;" syntax.
300                                metadata[i][2] = ReplaceString(";", value, " :semicolon: ")
301                        ENDIF
302                ENDIF
303        ENDFOR
304END
305
306// ==================================================================
307
308FUNCTION CS_fileExists(fileName)
309        STRING fileName
310        VARIABLE refNum
311        Open/R/Z/P=home refNum as fileName
312        IF (V_flag == 0)
313                CLOSE refNum
314        ENDIF
315        RETURN( !V_flag )
316END
317
318// ==================================================================
319
320FUNCTION CS_appendMetaData(key, xpath, value)
321        STRING key, xpath, value
322        WAVE/T metadata
323        VARIABLE last
324        last = DimSize(metadata, 0)
325        Redimension/N=(last+1, 3) metadata
326        metadata[last][0] = key
327        metadata[last][1] = xpath
328        metadata[last][2] = value
329END
330
331// ==================================================================
332
333FUNCTION CS_findElementIndex(matchStr)
334        //
335        // support the canSAS XML file reader
336        // return index where   W_ElementList[index][0] == matchStr
337        // return -1 if not found
338        //
339        // not dependent on the version of the canSAS XML file being read
340        //
341        STRING matchStr
342        WAVE/T W_ElementList
343        VARIABLE i
344        FOR (i = 0; i < numpnts(W_ElementList); i += 1)
345                IF ( CmpStr(W_ElementList[i][0], matchStr)  == 0 )
346                        RETURN(i)
347                ENDIF
348        ENDFOR
349        RETURN(-1)
350END
351
352// ==================================================================
353
354FUNCTION CS_registerNameSpaces()
355        //
356        // identify the namespaces in use by the XML file described in W_ElementList
357        // build a registry for later use that assigns a prefix to each unique namespace
358        // build a reverse registry as well to identify the keyword
359        //
360        WAVE/T W_ElementList
361        STRING thisNs
362        STRING thisKey = "ns"
363        STRING/G nsRegistry = ""
364        STRING/G reverseRegistry = ""
365        STRING/G keySep = "=", listSep = ";"
366        VARIABLE i
367        // first, identify all the namespaces in use by looking at  W_ElementList[][1]
368        FOR (i = 0; i < numpnts(W_ElementList); i += 1)
369                thisNs = W_ElementList[i][1]
370                // value does not matter now, we'll fix that later
371                reverseRegistry = ReplaceStringByKey(thisNs, reverseRegistry, thisKey, keySep, listSep)
372        ENDFOR
373        // next, create the registry by indexing each namespace
374        FOR (i = 0; i < ItemsInList(reverseRegistry, listSep); i += 1)
375                thisNs = StringFromList(0, StringFromList(i, reverseRegistry, listSep), keySep)
376                thisKey = "ns" + num2str(i)
377                nsRegistry = ReplaceStringByKey(thisKey, nsRegistry, thisNs, keySep, listSep)
378                // don't forget to assign the proper key name as the value in the reverse registry
379                reverseRegistry = ReplaceStringByKey(thisNs, reverseRegistry, thisKey, keySep, listSep)
380        ENDFOR
381        RETURN(0)
382END
383
384// ==================================================================
385
386FUNCTION/S CS_GetNameSpaceByKey(key)
387        STRING key
388        STRING ns
389        SVAR nsRegistry
390        SVAR keySep
391        SVAR listSep
392        ns = StringByKey(key, nsRegistry, keySep, listSep)
393        RETURN(ns)
394END
395
396// ==================================================================
397
398FUNCTION/S CS_GetKeyByNameSpace(ns)
399        STRING ns
400        STRING key
401        SVAR reverseRegistry
402        SVAR keySep
403        SVAR listSep
404        key = StringByKey(ns, reverseRegistry, keySep, listSep)
405        RETURN(key)
406END
407
408// ==================================================================
409
410FUNCTION/S CS_XPath_NS(simpleStr)
411        // namespaces complicate the XPath description
412        // this function adds namespace info as necessary to simpleStr (an XPath)
413        STRING simpleStr
414        SVAR nsPre
415        STRING result = "", thisChar, lastChar = ""
416        VARIABLE i
417        FOR (i = 0; i < strlen(simpleStr); i += 1)
418                //PRINT simpleStr[i]
419                thisChar = simpleStr[i]
420                IF ( CmpStr(lastChar, "/") == 0 )
421                        STRSWITCH (thisChar)
422                                CASE "/":
423                                CASE "@":
424                                        BREAK
425                                DEFAULT:
426                                        result += nsPre
427                        ENDSWITCH
428                ENDIF
429                result += thisChar
430                lastChar = thisChar
431        ENDFOR
432        RETURN(result)
433END
434
435// ==================================================================
436
437FUNCTION/S CS_buildXpathStr(prefix, value)
438        STRING prefix, value
439        SVAR nsPre
440        STRING XPathStr = ""
441        // namespaces complicate the XPath description
442        // this function can be used only with very simple XPath constructions
443        IF (strlen(nsPre) > 0)
444                XPathStr = prefix + nsPre + value
445        ELSE
446                XPathStr = prefix + value
447        ENDIF
448        RETURN(XPathStr)
449END
450
451// ==================================================================
452
453FUNCTION/S CS_XmlStrFmXpath(fileID, prefix, value)
454        VARIABLE fileID
455        STRING prefix, value
456        SVAR nsStr
457        STRING result
458        result = TrimWS(XmlStrFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, ""))
459        RETURN( result )
460END
461
462// ==================================================================
463
464FUNCTION CS_simpleXmlWaveFmXpath(fileID, prefix, value)
465        VARIABLE fileID
466        STRING prefix, value
467        SVAR nsStr
468        XMLwaveFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, " ")
469        // output: M_xmlContent  W_xmlContentNodes
470END
471
472// ==================================================================
473
474FUNCTION CS_simpleXmlListXpath(fileID, prefix, value)
475        VARIABLE fileID
476        STRING prefix, value
477        SVAR nsStr
478        XMLlistXpath(fileID, prefix + CS_XPath_NS(value), nsStr)                // output: W_listXPath
479END
480
481// ==================================================================
482
483Function/T   TrimWS(str)
484    // TrimWhiteSpace (code from Jon Tischler)
485    String str
486    str = TrimWSL(str)
487    str = TrimWSR(str)
488    return str
489End
490
491// ==================================================================
492
493Function/T   TrimWSL(str)
494    // TrimWhiteSpaceLeft (code from Jon Tischler)
495    String str
496    Variable i, N=strlen(str)
497    for (i=0;char2num(str[i])<=32 && i<N;i+=1)    // find first non-white space
498    endfor
499    return str[i,Inf]
500End
501
502// ==================================================================
503
504Function/T   TrimWSR(str)
505    // TrimWhiteSpaceRight (code from Jon Tischler)
506    String str
507    Variable i
508    for (i=strlen(str)-1; char2num(str[i])<=32 && i>=0; i-=1)    // find last non-white space
509    endfor
510    return str[0,i]
511End
512
513// ==================================================================
514
515FUNCTION CS_updateWaveNote(wavName, key, value)
516        STRING wavName, key, value
517        STRING wavenote
518        wavenote = ReplaceStringByKey(key, note($wavName), value)
519        Note /K $wavName, wavenote
520END
521
522// ==================================================================
523
524FUNCTION CS_1i_extractIdataColumn2Wave(fileID, basePath, colName, wavName)
525        //
526        // this function pulls one column of data from each <Idata> element
527        // easier to write this as a function than debug it all the times it is needed
528        //
529        VARIABLE fileID
530        STRING basePath, colName, wavName
531        STRING unit
532        WAVE/T metadata
533        VARIABLE i
534
535        //      Q values come out in multiple columns. Different nodes means different columns in M_xmlcontent
536        //      Multiple values in the SAME node (i.e. a vector) get put in different rows.
537        //      We are therefore going to transpose the wave
538        //      (Based on example from Andrew R.J. Nelson.)
539        CS_simpleXmlWaveFmXpath(fileID, basePath, "//Idata/" + colName)
540        WAVE/T  M_xmlcontent, W_xmlcontentnodes
541        IF (numpnts(M_XMLcontent) > 0)
542                MatrixTranspose M_XMLcontent
543                MAKE/O/D/N=(numpnts(M_XMLcontent)) $wavName = str2num(M_xmlcontent[p][0])
544                // don't forget the units!  Assume that all rows have the same as the first row.
545                FOR (i = 0; i < DimSize(metadata, 0); i += 1)
546                        IF (strlen(metadata[i][2]) > 0)
547                                // only add defined metadata to the wavenote
548                                CS_updateWaveNote(wavName, metadata[i][0], metadata[i][2])
549                        ENDIF
550                ENDFOR
551                unit = CS_XmlStrFmXpath(fileID, basePath, "/Idata[1]/"+colName+"/@unit")
552                SetScale d 0, 1, unit, $wavName                         // update the wave's "UNITS" string
553                SetScale x 0, 1, unit, $wavName                         // put it here, too, for the Data Browser
554                CS_updateWaveNote(wavName, "unit", unit)                // put UNIT in wavenote
555        ENDIF
556END
557
558// ==================================================================
559
560FUNCTION CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder)
561        //
562        // extract data from the SASdata/Idata block in a canSAS1d/v1.0 XML file
563        //  (1i in the function name signifies this is a function that supports INPUT from version 1.0 XML files)
564        //
565        VARIABLE fileID
566        STRING SASdataPath, SASdata_folder
567
568        // extract each Idata column into the waves: QQ, II, Qdev, Idev [Qmean] [Qfwhm] [Shadowfactor]
569        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Q",         "Qsas")
570        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "I",         "Isas")
571        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qdev",      "Qdev")
572        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Idev",      "Idev")
573        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qmean",     "Qmean")
574        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qfwhm",     "Qfwhm")
575        CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Shadowfactor",      "Shadowfactor")
576        // this looks too simple!
577
578        // move the waves to the sample folder
579        // !!!!! Missing Qsas, Isas, Qdev, and/or Idev are a broken data set
580        //              This should produce an exception.
581        //              Best to return an error code but the caller chain is not ready to pass that to the top level, yet.
582        IF (exists("Qsas") == 1)
583                MoveWave Qsas, $SASdata_folder
584        ENDIF
585        IF (exists("Isas") == 1)
586                MoveWave Isas, $SASdata_folder
587        ENDIF
588        IF (exists("Qdev") == 1)
589                MoveWave Qdev, $SASdata_folder
590        ENDIF
591        IF (exists("Idev") == 1)
592                MoveWave Idev, $SASdata_folder
593        ENDIF
594        IF (exists("Qmean") == 1)
595                MoveWave Qmean, $SASdata_folder
596        ENDIF
597        IF (exists("Qfwhm") == 1)
598                MoveWave Qfwhm, $SASdata_folder
599        ENDIF
600        IF (exists("ShadowFactor") == 1)
601                MoveWave ShadowFactor, $SASdata_folder
602        ENDIF
603END
604
605
606// ==================================================================
607// ==================================================================
608// ==================================================================
609
610
611FUNCTION prj_grabMyXmlData()
612        STRING srcDir = "root:Packages:CS_XMLreader"
613        STRING destDir = "root:PRJ_canSAS"
614        STRING srcFolder, destFolder, theFolder
615        Variable i
616        NewDataFolder/O  $destDir               // for all my imported data
617        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 )
618                theFolder = GetIndexedObjName(srcDir, 4, i)
619                srcFolder = srcDir + ":" + theFolder
620                destFolder = destDir + ":" + theFolder
621                // PRINT srcFolder, destFolder
622                IF (DataFolderExists(destFolder))
623                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
624                        // need to find unique name for destination
625                        // Persons who implement this properly should be more elegant
626                        // For now, I will blast the existing and proceed blindly.
627                        KillDataFolder/Z  $destFolder           // clear out any previous work
628                        DuplicateDataFolder $srcFolder, $destFolder
629                ELSE
630                        DuplicateDataFolder $srcFolder, $destFolder
631                ENDIF
632        ENDFOR
633END
634
635FUNCTION prjTest_cansas1d()
636        // unit tests for the routines under prj-readXML.ipf
637        STRING theFile
638        STRING fList = ""
639        VARIABLE i
640        // build a table of test data sets
641        fList = AddListItem("elmo.xml",                                 fList, ";", Inf)                // non-existent file
642        fList = AddListItem("bimodal-test1.xml",                fList, ";", Inf)                // simple dataset
643        fList = AddListItem("bimodal-test2-vector.xml", fList, ";", Inf)                // version 2.0 file (no standard yet)
644        fList = AddListItem("test.xml",                                 fList, ";", Inf)                // cs_collagen.xml with no namespace
645        fList = AddListItem("test2.xml",                                fList, ";", Inf)                // version 2.0 file (no standard yet)
646        fList = AddListItem("cs_collagen.xml",                  fList, ";", Inf)                // another simple dataset, bare minimum info
647        fList = AddListItem("cs_collagen_full.xml",             fList, ";", Inf)                // more Q range than previous
648        fList = AddListItem("cs_af1410.xml",                    fList, ";", Inf)                // multiple SASentry and SASdata elements
649        fList = AddListItem("1998spheres.xml",                  fList, ";", Inf)                // 2 SASentry, few thousand data points each
650        fList = AddListItem("does-not-exist-file.xml",          fList, ";", Inf)                // non-existent file
651        // try to load each data set in the table
652        FOR ( i = 0; i < ItemsInList(fList) ; i += 1 )
653                theFile = StringFromList(i, fList)                                      // walk through all test files
654                // PRINT "file: ", theFile
655                IF (CS_XmlReader(theFile) == 0)                                 // did the XML reader return without an error code?
656                        prj_grabMyXmlData()                                             // move the data to my directory
657                ENDIF
658        ENDFOR
659END
Note: See TracBrowser for help on using the repository browser.