/* * GeneralDataTypeParser.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.evoxml; import dr.evolution.datatype.DataType; import dr.evolution.datatype.GeneralDataType; import dr.xml.*; import dr.util.Attribute; import dr.util.Identifiable; import java.util.ArrayList; import java.util.List; /** * The XML for a nucleotide data type under this scheme would be: * <generalDataType id="nucleotides"> * <state code="A"/> * <state code="C"/> * <state code="G"/> * <state code="T"/> * <alias code="U" state="T"/> * <ambiguity code="R" states="AG"/> * <ambiguity code="Y" states="CT"/> * <ambiguity code="?" states="ACGT"/> * <ambiguity code="-" states="ACGT"/> * </generalDataType> * * @author Andrew Rambaut * @author Alexei Drummond * * @version $Id: GeneralDataTypeParser.java,v 1.2 2005/05/24 20:25:59 rambaut Exp $ */ public class GeneralDataTypeParser extends AbstractXMLObjectParser { /** * Name of data type. For XML and human reading of data type. */ public static final String GENERAL_DATA_TYPE = "generalDataType"; public static final String STATE = "state"; public static final String STATES = "states"; public static final String ALIAS = "alias"; public static final String AMBIGUITY = "ambiguity"; public static final String CODE = "code"; public String getParserName() { return GENERAL_DATA_TYPE; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { List<String> states = new ArrayList<String>(); for (int i =0; i < xo.getChildCount(); i++) { if (xo.getChild(i) instanceof XMLObject) { XMLObject cxo = (XMLObject)xo.getChild(i); if (cxo.getName().equals(STATE)) { states.add(cxo.getStringAttribute(CODE)); } else if (cxo.getName().equals(ALIAS)) { // Do nothing just now } else if (cxo.getName().equals(AMBIGUITY)) { // Do nothing just now } else { throw new XMLParseException("illegal element, " + cxo.getName() + ", in " + getParserName() + " element"); } } else if (xo.getChild(i) instanceof Identifiable) { states.add(((Identifiable)xo.getChild(i)).getId()); } else { throw new XMLParseException("illegal element in " + getParserName() + " element"); } } if (states.size() == 0) { throw new XMLParseException("No state elements defined in " + getParserName() + " element"); } else if (states.size() < 2 ) { throw new XMLParseException("Less than two state elements defined in " + getParserName() + " element"); } GeneralDataType dataType = new GeneralDataType(states); for (int i =0; i < xo.getChildCount(); i++) { if (xo.getChild(i) instanceof XMLObject) { XMLObject cxo = (XMLObject)xo.getChild(i); if (cxo.getName().equals(ALIAS)) { String alias = cxo.getStringAttribute(CODE); // if (alias.length() != 1) { // throw new XMLParseException("State alias codes in " + getParserName() + " element must be exactly one character"); // } String state = cxo.getStringAttribute(STATE); // if (state.length() != 1) { // throw new XMLParseException("State codes in " + getParserName() + " element must be exactly one character"); // } try { dataType.addAlias(alias, state); } catch (IllegalArgumentException iae) { throw new XMLParseException(iae.getMessage() + "in " + getParserName() + " element"); } } else if (cxo.getName().equals(AMBIGUITY)) { String code = cxo.getStringAttribute(CODE); // if (code.length() != 1) { // throw new XMLParseException("State ambiguity codes in " + getParserName() + " element must be exactly one character"); // } String[] ambiguities = cxo.getStringArrayAttribute(STATES); if (ambiguities.length == 1) { String codes = ambiguities[0]; if (codes.length() < 2) { throw new XMLParseException("States for ambiguity code in " + getParserName() + " element are not ambiguous"); } ambiguities = new String[codes.length()]; for (int j = 0; j < codes.length(); j++) { ambiguities[j] = String.valueOf(codes.charAt(j)); } } try { dataType.addAmbiguity(code, ambiguities); } catch (IllegalArgumentException iae) { throw new XMLParseException(iae.getMessage() + "in " + getParserName() + " element"); } } } } return dataType; } //************************************************************************ // AbstractXMLObjectParser implementation //************************************************************************ public String getParserDescription() { return "Defines a general DataType for any number of states"; } public String getExample() { return "<!-- The XML for a nucleotide data type under this scheme would be -->\n"+ "<generalDataType id=\"nucleotides\">\n"+ " <state code=\"A\"/>\n"+ " <state code=\"C\"/>\n"+ " <state code=\"G\"/>\n"+ " <state code=\"T\"/>\n"+ " <alias code=\"U\" state=\"T\"/>\n"+ " <ambiguity code=\"R\" states=\"AG\"/>\n"+ " <ambiguity code=\"Y\" states=\"CT\"/>\n"+ " <ambiguity code=\"?\" states=\"ACGT\"/>\n"+ " <ambiguity code=\"-\" states=\"ACGT\"/>\n"+ "</generalDataType>\n"; } public Class getReturnType() { return DataType.class; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private XMLSyntaxRule[] rules = new XMLSyntaxRule[] { new ElementRule(Identifiable.class, 0, Integer.MAX_VALUE), new ContentRule("<state code=\"X\"/>"), new ContentRule("<alias code=\"Y\" state=\"X\"/>"), new ContentRule("<ambiguity code=\"Z\" states=\"XY\"/>") }; }