package org.autoplot.metatree; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Scanner; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.autoplot.datasource.LogNames; import org.das2.qds.DataSetOps; import org.das2.qds.DataSetUtil; import org.das2.qds.QDataSet; import org.autoplot.datasource.MetadataModel; import org.das2.datum.LoggerManager; import org.w3c.dom.Node; /** * * @author jbf */ public class MetadataUtil { private static final Logger logger= LoggerManager.getLogger(LogNames.APDSS); /** * converts tree model node into canonical Map. Branch nodes * are HashMap as well. * @param node * @return */ public static Map toMetaTree( Node node ) { Map result= new LinkedHashMap<>(); Node child= node.getFirstChild(); while ( child!=null ) { Object value; if ( child.hasChildNodes() ) { value= toMetaTree( child ); } else { value= child.getNodeValue(); } result.put( child.getNodeName(), value ); child= child.getNextSibling(); } return result; } /** * get the code for the path. * @param node the root node * @param path the name for each level to pick. * @return the node at this point */ public static Node getNode( Node node, String[] path ) { int i=0; Node child= node.getFirstChild(); while ( i tree, String[] path ) { int i=0; Object child= tree.get( path[0] ); i++; while ( i sliceProperties(Map properties, int sliceDimension) { return org.das2.qds.DataSetOps.sliceProperties(properties, sliceDimension); } /** * swap DEPEND_0 and DEPEND_1 and pass on the rest. * @param properties * @return */ public static Map transposeProperties(Map properties) { Map result = new LinkedHashMap(); String[] ss= DataSetUtil.dimensionProperties(); for ( String s: ss ) { Object val= properties.get(s); if ( val!=null ) result.put( s, val ); } if ( properties.get("DEPEND_0")!=null ) result.put("DEPEND_1", properties.get("DEPEND_0")); if ( properties.get("DEPEND_1")!=null ) result.put("DEPEND_0", properties.get("DEPEND_1")); return result; } /** * run the DataSource-provided properties through sprocess. * TODO: this has not been implemented for most operations, and this all needs to be reconsidered * @param c * @param properties * @return */ public static Map sprocess( String c, Map properties ) { int i= c.indexOf('|'); if ( i>0 ) { c= c.substring(i); // TODO: look at the slice component. } Scanner s= new Scanner( c ); s.useDelimiter("[\\(\\),]"); while ( s.hasNext() ) { String cmd= s.next(); if ( cmd.trim().length()==0 ) continue; if ( cmd.equals("|slices") ) { Pattern skipPattern= Pattern.compile("\\':?\\'"); List args= new ArrayList(); while ( s.hasNextInt() || s.hasNext( skipPattern ) ) { if ( s.hasNextInt() ) { args.add( s.nextInt() ); } else { args.add( s.next() ); } } for ( int idim=args.size()-1; idim>=0; idim-- ) { if ( args.get(idim) instanceof Integer ) { properties= sliceProperties( properties, idim ); } } } else if ( cmd.startsWith("|slice") ) { int dim= cmd.charAt(6)-'0'; s.next(); properties= sliceProperties( properties, dim ); } else if ( cmd.startsWith("|collapse") ) { int dim= cmd.charAt(9)-'0'; properties= sliceProperties( properties, dim ); if ( s.hasNextInt() ) { int st= s.nextInt(); int en= s.nextInt(); logger.fine("not using st and en: "+st+","+en); } } else if ( cmd.startsWith("|total") && cmd.length()==7 ) { int dim= cmd.charAt(6)-'0'; properties= sliceProperties( properties, dim ); } else if ( cmd.startsWith("|total") && cmd.length()==6 ) { int dim= s.nextInt(); properties= sliceProperties( properties, dim ); } else if ( cmd.startsWith("|collapse") && cmd.length()==10 ) { int dim= cmd.charAt(9)-'0'; properties= sliceProperties( properties, dim ); } else if ( cmd.equals("|autoHistogram") ) { Map newproperties= new HashMap(); newproperties.put( QDataSet.DEPEND_0, properties ); properties= newproperties; } else if ( cmd.equals("|transpose") ) { properties= transposeProperties(properties); } else if ( cmd.equals("|smooth") ) { // do nothing } else if ( cmd.equals("|trim") ) { // do nothing } else if ( cmd.equals("|detrend") ) { // do nothing } else if ( cmd.equals("|medianFilter") ) { // do nothing } else if ( cmd.equals("|nop") ) { // do nothing } else if ( cmd.equals("|copy") ) { // do nothing } else { return new HashMap(); } } return properties; } /** * return the MetadataModel object for this identifier, or null. * @param t the id of the model, such as "ISTP-CDF", or null. * @return */ public static MetadataModel getMetadataModel( String t ) { if ( t==null ) return null; if ( t.equals(QDataSet.VALUE_METADATA_MODEL_ISTP ) ) { return new IstpMetadataModel(); } else if ( t.equals( QDataSet.VALUE_METADATA_MODEL_SPASE ) ) { return new SpaseMetadataModel(); } else { return null; } } /** * converts IDL and Fortran-style specs (F7.2) to Java/C style (%7.2f), or * returns null when this cannot be done. * @param spec Java or Fortran style format * @return null if no conversion can be made, or Java style * @see String#format(java.lang.String, java.lang.Object...) * @see org.das2.qds.util.AsciiParser#getRegexForFormat(java.lang.String) */ public static String normalizeFormatSpecifier( String spec ) { Pattern p= Pattern.compile("([FDEGI])((\\d+)(\\.(\\d+)))"); Pattern j= Pattern.compile("\\%(\\d+)(\\.(\\d+))([fdox])"); if ( j.matcher(spec).matches() ) { return spec; } else { Matcher pm= p.matcher(spec); if ( !pm.matches() ) { return null; } else { char c= pm.group(1).charAt(0); if ( c=='G' ) c= 'E'; if ( c=='D' ) c= 'F'; return "%"+pm.group(2)+Character.toLowerCase(c); } } } }