001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.align.xml;
022
023import java.io.IOException;
024import java.io.StringReader;
025import java.util.ArrayList;
026import java.util.List;
027
028import javax.vecmath.Matrix4d;
029import javax.xml.parsers.DocumentBuilder;
030import javax.xml.parsers.DocumentBuilderFactory;
031import javax.xml.parsers.ParserConfigurationException;
032
033import org.biojava.nbio.structure.StructureIdentifier;
034import org.biojava.nbio.structure.align.client.StructureName;
035import org.biojava.nbio.structure.align.multiple.Block;
036import org.biojava.nbio.structure.align.multiple.BlockImpl;
037import org.biojava.nbio.structure.align.multiple.BlockSet;
038import org.biojava.nbio.structure.align.multiple.BlockSetImpl;
039import org.biojava.nbio.structure.align.multiple.MultipleAlignment;
040import org.biojava.nbio.structure.align.multiple.MultipleAlignmentEnsemble;
041import org.biojava.nbio.structure.align.multiple.MultipleAlignmentEnsembleImpl;
042import org.biojava.nbio.structure.align.multiple.MultipleAlignmentImpl;
043import org.biojava.nbio.structure.align.multiple.ScoresCache;
044import org.w3c.dom.Document;
045import org.w3c.dom.NamedNodeMap;
046import org.w3c.dom.Node;
047import org.w3c.dom.NodeList;
048import org.xml.sax.InputSource;
049import org.xml.sax.SAXException;
050
051/**
052 * Parse an XML file representing a {@link MultipleAlignmentEnsemble}, so
053 * that the original alignment can be recovered.
054 * <p>
055 * Atoms need to be downloaded, either manually or using the method
056 * getAtomArrays() in MultipleAlignmentEnsemble.
057 *
058 * @author Aleix Lafita
059 * @since 4.1.1
060 *
061 */
062public class MultipleAlignmentXMLParser {
063
064        /**
065         * Creates a list of MultipleAlignment ensembles from an XML file.
066         * This recovers only the information that was previously stored.
067         * If the Atoms are needed, the method getAtomArrays() will automatically
068         * download the structures from the stored structure identifiers.
069         *
070         * @param xml String XML file containing any number of ensembles
071         * @return List of ensembles in the file
072         * @throws ParserConfigurationException
073         * @throws SAXException
074         * @throws IOException
075         */
076        public static List<MultipleAlignmentEnsemble> parseXMLfile(String xml)
077                        throws ParserConfigurationException, SAXException, IOException {
078
079                List<MultipleAlignmentEnsemble> ensembles =
080                                new ArrayList<MultipleAlignmentEnsemble>();
081
082                //Convert string to XML document
083                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
084                DocumentBuilder db = factory.newDocumentBuilder();
085                InputSource inStream = new InputSource();
086                inStream.setCharacterStream(new StringReader(xml));
087                Document doc = db.parse(inStream);
088                doc.getDocumentElement().normalize();
089
090                //In case there are more than one ensemble in the document (generalize)
091                NodeList listOfEnsembles =
092                                doc.getElementsByTagName("MultipleAlignmentEnsemble");
093
094                //Explore all the ensembles, if multiple ones
095                for (int e=0; e<listOfEnsembles.getLength(); e++) {
096
097                        Node root = listOfEnsembles.item(e);
098                        MultipleAlignmentEnsemble ensemble = parseEnsemble(root);
099                        ensembles.add(ensemble);
100                }
101                return ensembles;
102        }
103
104        private static MultipleAlignmentEnsemble parseEnsemble(Node root){
105
106                MultipleAlignmentEnsemble ensemble =
107                                new MultipleAlignmentEnsembleImpl();
108
109                parseHeader(root, ensemble);
110
111                NodeList children = root.getChildNodes();
112
113                for (int i=0; i<children.getLength(); i++) {
114
115                        Node child = children.item(i);
116                        if (child.getNodeName().equals("MultipleAlignment")){
117                                parseMultipleAlignment(child, ensemble);
118                        }
119                        else if (child.getNodeName().equals("Structures")){
120                                parseStructures(child, ensemble);
121                        }
122                        else if (child.getNodeName().equals("ScoresCache")){
123                                parseScoresCache(child, ensemble);
124                        }
125                }
126
127                return ensemble;
128        }
129
130        private static MultipleAlignment parseMultipleAlignment(Node root,
131                        MultipleAlignmentEnsemble ensemble) {
132
133                MultipleAlignment msa = new MultipleAlignmentImpl(ensemble);
134                NodeList children = root.getChildNodes();
135
136                for (int i=0; i<children.getLength(); i++) {
137
138                        Node child = children.item(i);
139
140                        if (child.getNodeName().equals("BlockSet")){
141                                parseBlockSet(child, msa);
142                        }
143                        else if (child.getNodeName().equals("ScoresCache")){
144                                parseScoresCache(child, msa);
145                        }
146                }
147                return msa;
148        }
149
150        private static BlockSet parseBlockSet(Node root, MultipleAlignment msa) {
151
152                BlockSet bs = new BlockSetImpl(msa);
153                List<Matrix4d> transforms = new ArrayList<Matrix4d>();
154                NodeList children = root.getChildNodes();
155
156                for (int i=0; i<children.getLength(); i++) {
157
158                        Node child = children.item(i);
159
160                        if (child.getNodeName().equals("Block")){
161                                parseBlock(child, bs);
162                        }
163                        else if (child.getNodeName().equals("Matrix4d")){
164                                Matrix4d t = parseMatrix4d(child);
165                                transforms.add(t);
166                        }
167                        else if (child.getNodeName().equals("ScoresCache")){
168                                parseScoresCache(child, bs);
169                        }
170                }
171                //Because if it is 0 means that there were no transformations
172                if (transforms.size() != 0){
173                        bs.setTransformations(transforms);
174                }
175                return bs;
176        }
177
178        private static Block parseBlock(Node root, BlockSet blockSet) {
179
180                Block b = new BlockImpl(blockSet);
181                List<List<Integer>> alignRes = new ArrayList<List<Integer>>();
182                b.setAlignRes(alignRes);
183                NodeList children = root.getChildNodes();
184
185                for(int i=0; i<children.getLength(); i++) {
186
187                        Node child = children.item(i);
188                        if (child.getNodeName().contains("eqr")){
189
190                                NamedNodeMap atts = child.getAttributes();
191
192                                int str = 1;
193                                Node node = atts.getNamedItem("str"+str);
194
195                                while (node!=null){
196
197                                        if (alignRes.size() < str) {
198                                                alignRes.add(new ArrayList<Integer>());
199                                        }
200
201                                        String residue = node.getTextContent();
202                                        if (residue.equals("null")){
203                                                alignRes.get(str-1).add(null);
204                                        } else {
205                                                alignRes.get(str-1).add(new Integer(residue));
206                                        }
207
208                                        str++;
209                                        node = atts.getNamedItem("str"+str);
210                                }
211                        }
212                        else if (child.getNodeName().equals("ScoresCache")){
213                                parseScoresCache(child, b);
214                        }
215                }
216                return b;
217        }
218
219        private static Matrix4d parseMatrix4d(Node node) {
220
221                Matrix4d m = new Matrix4d();
222                NamedNodeMap atts = node.getAttributes();
223
224                for (int x=0; x<4; x++){
225                        for (int y=0; y<4; y++){
226                                String key = "mat"+(x+1)+(y+1);
227                                String value = atts.getNamedItem(key).getTextContent();
228                                m.setElement(x, y, new Double(value));
229                        }
230                }
231                return m;
232        }
233
234        private static void parseScoresCache(Node root, ScoresCache cache) {
235
236                NodeList children = root.getChildNodes();
237
238                for (int i=0; i<children.getLength(); i++) {
239
240                        Node child = children.item(i);
241                        NamedNodeMap atts = child.getAttributes();
242                        if (atts != null) {
243                                Node score = atts.getNamedItem("value");
244                                Double value = new Double(score.getTextContent());
245                                cache.putScore(child.getNodeName(), value);
246                        }
247                }
248        }
249
250        private static void parseHeader(Node node,
251                        MultipleAlignmentEnsemble ensemble) {
252
253                NamedNodeMap atts = node.getAttributes();
254
255                String algo = atts.getNamedItem("Algorithm").getTextContent();
256                if (!algo.equals("null")){
257                        ensemble.setAlgorithmName(algo);
258                }
259
260                String version = atts.getNamedItem("Version").getTextContent();
261                if (!version.equals("null")){
262                        ensemble.setVersion(version);
263                }
264
265                String ioTime = atts.getNamedItem("IOTime").getTextContent();
266                if (!ioTime.equals("null")){
267                        ensemble.setIoTime(new Long(ioTime));
268                }
269
270                String time = atts.getNamedItem("CalculationTime").getTextContent();
271                if (!time.equals("null")){
272                        ensemble.setCalculationTime(new Long(time));
273                }
274        }
275
276        private static void parseStructures(Node root,
277                        MultipleAlignmentEnsemble ensemble) {
278
279                List<StructureIdentifier> names = new ArrayList<StructureIdentifier>();
280                ensemble.setStructureIdentifiers(names);
281
282                NamedNodeMap atts = root.getAttributes();
283
284                int str = 1;
285                Node node = atts.getNamedItem("name"+str);
286
287                while (node!=null){
288
289                        String name = node.getTextContent();
290                        names.add(new StructureName(name));
291
292                        str++;
293                        node = atts.getNamedItem("name"+str);
294                }
295        }
296
297}