/* RawSignalDescriptorReader.java created 2008-01-28
*
*/
package org.signalml.domain.signal.raw;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.log4j.Logger;
import org.signalml.app.util.SingleNameSpaceContext;
import org.signalml.domain.montage.system.EegSystemName;
import org.signalml.domain.signal.raw.RawSignalDescriptor.SourceSignalType;
import org.signalml.plugin.export.SignalMLException;
import org.signalml.util.FormatUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This class is responsible for reading the
* {@link RawSignalDescriptor description} of a raw signal from XML file.
* TODO add link to example file (need to put it somewhere it the web).
*
* @author Michal Dobaczewski © 2007-2008 CC Otwarte Systemy Komputerowe Sp. z o.o.
*/
public class RawSignalDescriptorReader {
protected static final Logger logger = Logger.getLogger(RawSignalDescriptorReader.class);
/**
* Converts the given document element to the
* {@link RawSignalDescriptor description} of a raw signal
* @param rawSignalEl the document element to be converted
* @return the created description of a raw signal
* @throws SignalMLException if the element doesn't contain a valid
* description of a raw signal
*/
public RawSignalDescriptor getDescriptor(Element rawSignalEl) throws SignalMLException {
RawSignalDescriptor descriptor = new RawSignalDescriptor();
XPathFactory pathFactory = XPathFactory.newInstance();
XPath path = pathFactory.newXPath();
path.setNamespaceContext(new SingleNameSpaceContext("rs", RawSignalDocumentBuilder.NAMESPACE_URI));
try {
String exportFileName = path.evaluate(RawSignalDocumentBuilder.EXPORT_FILE_NAME, rawSignalEl);
descriptor.setExportFileName(exportFileName);
String sourceFileName = path.evaluate(RawSignalDocumentBuilder.SOURCE_FILE_NAME, rawSignalEl);
if (sourceFileName != null && !sourceFileName.isEmpty()) {
descriptor.setSourceFileName(sourceFileName);
}
boolean formatEstablished = false;
Element sourceFileFormatEl = (Element) path.evaluate(RawSignalDocumentBuilder.SOURCE_FILE_FORMAT, rawSignalEl, XPathConstants.NODE);
if (sourceFileFormatEl != null) {
Element signalMLSignalInfoEl = (Element) path.evaluate(RawSignalDocumentBuilder.SIGNALML_SIGNAL_INFO, sourceFileFormatEl, XPathConstants.NODE);
if (signalMLSignalInfoEl != null) {
descriptor.setSourceSignalType(SourceSignalType.SIGNALML);
descriptor.setSourceSignalMLFormat(path.evaluate(RawSignalDocumentBuilder.FORMAT, signalMLSignalInfoEl));
descriptor.setSourceSignalMLSourceUID(path.evaluate(RawSignalDocumentBuilder.SOURCE_UID, signalMLSignalInfoEl));
formatEstablished = true;
}
}
if (!formatEstablished) {
descriptor.setSourceSignalType(SourceSignalType.RAW);
}
descriptor.setSamplingFrequency(Float.parseFloat(path.evaluate(RawSignalDocumentBuilder.SAMPLING_FREQUENCY, rawSignalEl)));
int channelCount = Integer.parseInt(path.evaluate(RawSignalDocumentBuilder.CHANNEL_COUNT, rawSignalEl));
descriptor.setChannelCount(channelCount);
descriptor.setSampleCount(Integer.parseInt(path.evaluate(RawSignalDocumentBuilder.SAMPLE_COUNT, rawSignalEl)));
String calibration = path.evaluate(RawSignalDocumentBuilder.CALIBRATION, rawSignalEl);
if (calibration != null && !calibration.isEmpty()) {
descriptor.setCalibrationGain(Float.parseFloat(calibration));
} else {
descriptor.setCalibrationGain(1F);
}
descriptor.setSampleType(RawSignalSampleType.valueOf(path.evaluate(RawSignalDocumentBuilder.SAMPLE_TYPE, rawSignalEl)));
descriptor.setByteOrder(RawSignalByteOrder.valueOf(path.evaluate(RawSignalDocumentBuilder.BYTE_ORDER, rawSignalEl)));
String pageSize = path.evaluate(RawSignalDocumentBuilder.PAGE_SIZE, rawSignalEl);
if (pageSize != null && !pageSize.isEmpty()) {
descriptor.setPageSize(Float.parseFloat(pageSize));
}
String blocksPerPage = path.evaluate(RawSignalDocumentBuilder.BLOCKS_PER_PAGE, rawSignalEl);
if (blocksPerPage != null && !blocksPerPage.isEmpty()) {
descriptor.setBlocksPerPage(Integer.parseInt(blocksPerPage));
}
Element eegSystemNameNode = (Element) path.evaluate(RawSignalDocumentBuilder.EEG_SYSTEM_NAME, rawSignalEl, XPathConstants.NODE);
if (eegSystemNameNode != null) {
String symbol = path.evaluate(RawSignalDocumentBuilder.EEG_SYSTEM_SYMBOL, eegSystemNameNode);
String type = path.evaluate(RawSignalDocumentBuilder.EEG_SYSTEM_TYPE, eegSystemNameNode);
EegSystemName eegSystemName = new EegSystemName(symbol, type);
descriptor.setEegSystemName(eegSystemName);
}
Element channelLabelsEl = (Element) path.evaluate(RawSignalDocumentBuilder.CHANNEL_LABELS, rawSignalEl, XPathConstants.NODE);
if (channelLabelsEl != null && channelLabelsEl.hasChildNodes()) {
NodeList labelList = (NodeList) path.evaluate(RawSignalDocumentBuilder.LABEL, channelLabelsEl, XPathConstants.NODESET);
if (labelList != null) {
int labelCnt = labelList.getLength();
if (labelCnt > 0) {
String[] labels = new String[channelCount];
for (int i=0; i<channelCount; i++) {
if (i < labelCnt) {
labels[i] = labelList.item(i).getTextContent();
} else {
labels[i] = "L" + (i+1);
}
}
descriptor.setChannelLabels(labels);
}
}
}
String markerOffset = path.evaluate(RawSignalDocumentBuilder.MARKER_OFFSET, rawSignalEl);
if (markerOffset != null && !markerOffset.isEmpty()) {
descriptor.setMarkerOffset(Double.parseDouble(markerOffset));
}
String exportDate = path.evaluate(RawSignalDocumentBuilder.EXPORT_DATE, rawSignalEl);
if (exportDate != null && !exportDate.isEmpty()) {
try {
descriptor.setExportDate(FormatUtils.parseTime(exportDate));
} catch (ParseException ex) {
logger.error("Bad export date", ex);
throw new SignalMLException("error.invalidRawSignalXML");
}
}
Element gainElems = (Element) path.evaluate(RawSignalDocumentBuilder.CALIBRATION_GAIN, rawSignalEl, XPathConstants.NODE);
if (gainElems != null && gainElems.hasChildNodes()) {
NodeList paramList = (NodeList) path.evaluate(RawSignalDocumentBuilder.CALIBRATION_PARAM, gainElems, XPathConstants.NODESET);
if (paramList != null) {
int paramCount = paramList.getLength();
if (paramCount > 0) {
float[] params = new float[paramCount];
for (int i=0; i<paramCount; i++) {
if (i < paramCount) {
params[i] = Float.parseFloat(paramList.item(i).getTextContent());
} else {
params[i] = 1f;
}
}
descriptor.setCalibrationGain(params);
}
}
}
Element offsetElems = (Element) path.evaluate(RawSignalDocumentBuilder.CALIBRATION_OFFSET, rawSignalEl, XPathConstants.NODE);
if (offsetElems != null && offsetElems.hasChildNodes()) {
NodeList paramList = (NodeList) path.evaluate(RawSignalDocumentBuilder.CALIBRATION_PARAM, offsetElems, XPathConstants.NODESET);
if (paramList != null) {
int paramCount = paramList.getLength();
if (paramCount > 0) {
float[] params = new float[paramCount];
for (int i=0; i<paramCount; i++) {
if (i < paramCount) {
params[i] = Float.parseFloat(paramList.item(i).getTextContent());
} else {
params[i] = 1f;
}
}
descriptor.setCalibrationOffset(params);
}
}
}
else {
descriptor.setCalibrationOffset(0.0F);
}
String firstSampleTimestamp = path.evaluate(RawSignalDocumentBuilder.FIRST_SAMPLE_TIMESTAMP, rawSignalEl);
if (firstSampleTimestamp != null && !firstSampleTimestamp.isEmpty()) {
descriptor.setFirstSampleTimestamp(Double.parseDouble(firstSampleTimestamp));
}
String backup = path.evaluate(RawSignalDocumentBuilder.IS_BACKUP, rawSignalEl);
if (backup != null && !backup.isEmpty() && backup.equals("1")) {
descriptor.setIsBackup(true);
} else {
descriptor.setIsBackup(false);
}
} catch (XPathExpressionException ex) {
throw new SignalMLException("error.invalidRawSignalXML", ex);
}
return descriptor;
}
/**
* Reads the {@link RawSignalDescriptor description} of a raw signal
* from the given file
* @param file the file with the description of a raw signal
* @return the created description
* @throws IOException if the file is not a valid xml file or some
* other error while reading file
* @throws SignalMLException if the file doesn't contain a valid
* description of a raw signal
*/
public RawSignalDescriptor readDocument(File file) throws IOException, SignalMLException {
try {
Document document = RawSignalDocumentBuilder.getInstance().parse(file);
return getDescriptor(document.getDocumentElement());
} catch (SAXException ex) {
throw new SignalMLException("error.invalidRawSignalXML", ex);
}
}
}