uk.ac.starlink.votable.FieldElement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stil Show documentation
Show all versions of stil Show documentation
Starlink Tables Infrastructure Library
package uk.ac.starlink.votable;
import java.util.logging.Logger;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Table column characteristics represented by a FIELD element in a VOTable.
*
* @author Mark Taylor (Starlink)
*/
public class FieldElement extends VOElement {
private final boolean strict_;
private final static Logger logger_ =
Logger.getLogger( "uk.ac.starlink.votable" );
final static long ASSUMED_ARRAYSIZE = -2L;
/**
* Constructs a FieldElement from a DOM element.
*
* @param base FIELD element
* @param doc owner document for new element
*/
FieldElement( Element base, VODocument doc ) {
super( base, doc );
strict_ = doc.isStrict();
}
/**
* Returns the array size. The returned value is an array of
* long, with one element for each dimension.
* The final dimension only may have the value -1, which indicates
* that this dimension is unknown. All other elements will be positive.
*
* @return array giving dimensions of data in this field.
*/
public long[] getArraysize() {
int sliceSize = 1;
String as = hasAttribute( "datatype" )
? getAttribute( "arraysize" )
: "*";
as = as == null ? null : as.trim();
if ( as != null && as.length() > 0 ) {
String[] dimtxt = as.split( "x" );
int ndim = dimtxt.length;
long[] arraysize = new long[ ndim ];
for ( int i = 0; i < ndim; i++ ) {
if ( i == ndim - 1 && dimtxt[ i ].trim().endsWith( "*" ) ) {
arraysize[ i ] = -1;
}
else {
long dim;
try {
dim = Long.parseLong( dimtxt[ i ] );
}
catch ( NumberFormatException e ) {
dim = 1;
logger_.warning( "Bad arraysize element " + dimtxt[ i ]
+ " - assuming 1" );
}
if ( dim < 0 ) {
dim = 1;
logger_.warning( "Bad arraysize element " + dimtxt[ i ]
+ " - assuming 1" );
}
arraysize[ i ] = dim;
sliceSize *= arraysize[ i ];
}
}
return arraysize;
}
else {
return new long[ 0 ];
}
}
/**
* Returns the 'null' value for this FieldElement.
* This is the value of the 'null' attribute of the VALUES child
* with type='legal', or if that doesn't exist the 'null' attribute
* of the VALUES child with type='actual' (this is some kind of
* guesswork based on what is not written in the VOTable document).
* This has nothing to do with the java null value.
*
* @return the bad ("null") value or, confusingly, null if
* none is defined
*/
public String getNull() {
String blank = null;
for ( Node child = getFirstChild(); child != null;
child = child.getNextSibling() ) {
if ( child instanceof ValuesElement ) {
ValuesElement vals = (ValuesElement) child;
if ( blank == null || "legal".equals( vals.getType() ) ) {
blank = vals.getNull();
}
}
}
return blank;
}
/**
* Returns the value of the datatype attribute.
* If no datatype attribute has been defined (which is illegal, but
* not uncommon) then "char" will be returned.
*
* @return the datatype
*/
public String getDatatype() {
if ( hasAttribute( "datatype" ) ) {
return getAttribute( "datatype" );
}
else {
logger_.info( "Missing datatype attribute for " + getHandle() +
" - assume char(*)" );
return "char";
}
}
/**
* Returns the value of the unit attribute,
* or null if there is none.
*
* @return the unit string
*/
public String getUnit() {
return hasAttribute( "unit" ) ? getAttribute( "unit" ) : null;
}
/**
* Returns the value of the ucd attribute,
* or null if there is none.
*
* @return the ucd string
* @see uk.ac.starlink.table.UCD
*/
public String getUcd() {
return hasAttribute( "ucd" ) ? getAttribute( "ucd" ) : null;
}
/**
* Returns the value of the utype attribute,
* or null if there is none.
*
* @return the utype string
*/
public String getUtype() {
return hasAttribute( "utype" ) ? getAttribute( "utype" ) : null;
}
/**
* Returns the value of the xtype attribute,
* or null if there is none.
*
* @return the xtype string
*/
public String getXtype() {
return hasAttribute( "xtype" ) ? getAttribute( "xtype" ) : null;
}
/**
* Returns the index of this field in a given table; that is the
* index of the column it represents. The first FIELD child of a
* TABLE element has index 0, and so on.
* If this field is not associated with table, -1 is returned.
*
* @param table table within which to locate this field
* @return 0-based index of this field in table, or -1
*/
public int getIndexInTable( TableElement table ) {
FieldElement[] fields = table.getFields();
for ( int i = 0; i < fields.length; i++ ) {
if ( fields[ i ] == this ) {
return i;
}
}
return -1;
}
/**
* Returns a VALUES child of this element with the attribute
* type='legal', or null if none exists.
*
* @return the 'legal' Values object
*/
public ValuesElement getLegalValues() {
for ( Node child = getFirstChild(); child != null;
child = child.getNextSibling() ) {
if ( child instanceof ValuesElement &&
"legal".equals( ((ValuesElement) child).getType() ) ) {
return (ValuesElement) child;
}
}
return null;
}
/**
* Returns a VALUES child of this element with the attribute
* type='actual', or null if none exists.
*
* @return the 'actual' Values object
*/
public ValuesElement getActualValues() {
for ( Node child = getFirstChild(); child != null;
child = child.getNextSibling() ) {
if ( child instanceof ValuesElement &&
"actual".equals( ((ValuesElement) child).getType() ) ) {
return (ValuesElement) child;
}
}
return null;
}
/**
* Returns the COOSYS element corresponding to this field, if any.
*
* @return referenced element with tagname COOSYS, or null
*/
public VOElement getCoosys() {
return getReferencedElement( "ref", "COOSYS" );
}
/**
* Returns the TIMESYS element corresponding to this field, if any.
*
* @return referenced element with tagname TIMESYS, or null
*/
public TimesysElement getTimesys() {
VOElement el = getReferencedElement( "ref", "TIMESYS" );
return el instanceof TimesysElement ? (TimesysElement) el : null;
}
public String toString() {
String str = getHandle();
StringBuffer sbuf = new StringBuffer( str );
if ( hasAttribute( "datatype" ) ) {
sbuf.append( ' ' )
.append( getAttribute( "datatype" ) );
}
if ( hasAttribute( "arraysize" ) ) {
sbuf.append( " (" )
.append( getAttribute( "arraysize" ) )
.append( ")" );
}
if ( hasAttribute( "units" ) ) {
sbuf.append( " / " + getAttribute( "units" ) );
}
return sbuf.toString();
}
/**
* Returns the decoder object which knows how to turn raw data into
* usable objects. This is package-private for because it probably
* doesn't need to be public, but it (and the Decoder class itself)
* could be public if there was some reason for it to be so.
*/
Decoder getDecoder() {
/* Get information we need to create a decoder for this field. */
String datatype = getDatatype();
long[] arraysize = getArraysize();
String nul = getNull();
/* Doctor it. This is to work around the fact that many FIELD
* elements in practice omit an "arraysize='*'" attribute for
* character datatypes. According to a strict reading of the
* standard this means each data cell contains a single character.
* What is meant is almost always an N-character string though. */
if ( ( "char".equals( datatype ) ||
"unicodeChar".equals( datatype ) ) &&
arraysize.length == 0 ) {
if ( strict_ ) {
logger_.info( getHandle()
+ " - unspecified arraysize implies single"
+ " character for "
+ datatype + " datatype (strict)" );
}
else {
arraysize = new long[] { ASSUMED_ARRAYSIZE };
logger_.warning( getHandle()
+ " - assuming unspecified arraysize='*' for "
+ datatype + " datatype (non-strict)" );
}
}
/* Create a decoder. */
return Decoder.makeDecoder( datatype, arraysize, nul );
}
}