BioInfWeb - TreeGraph / Development / Source / Show File - NeXMLReader.java

TreeGraph2 subversion repository

sventon subversion web client - http://www.sventon.org
[show recent changes]
 
  Help
Rev: HEAD (815) - https://secure.bioinfweb.info/Code/svn/TreeGraph2 / trunk / main / src / info / bioinfweb / treegraph / document / io / jphyloio / NeXMLReader.java
Show File - NeXMLReader.java  [show properties]
spinner
/*
 * TreeGraph 2 - A feature rich editor for phylogenetic trees
 * Copyright (C) 2007-2011, 2013-2017  Ben Stöver, Sarah Wiechers, Kai Müller
 * <http://treegraph.bioinfweb.info/>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
10   * 
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   * GNU General Public License for more details.
15   * 
16   * You should have received a copy of the GNU General Public License
17   * along with this program. If not, see <http://www.gnu.org/licenses/>.
18   */
19  package info.bioinfweb.treegraph.document.io.jphyloio;
20 
21 
22  import info.bioinfweb.jphyloio.JPhyloIOEventReader;
23  import info.bioinfweb.jphyloio.ReadWriteParameterMap;
24  import info.bioinfweb.jphyloio.events.EdgeEvent;
25  import info.bioinfweb.jphyloio.events.JPhyloIOEvent;
26  import info.bioinfweb.jphyloio.events.LabeledIDEvent;
27  import info.bioinfweb.jphyloio.events.LinkedLabeledIDEvent;
28  import info.bioinfweb.jphyloio.events.NodeEvent;
29  import info.bioinfweb.jphyloio.events.meta.LiteralMetadataContentEvent;
30  import info.bioinfweb.jphyloio.events.meta.LiteralMetadataEvent;
31  import info.bioinfweb.jphyloio.events.meta.ResourceMetadataEvent;
32  import info.bioinfweb.jphyloio.events.meta.URIOrStringIdentifier;
33  import info.bioinfweb.jphyloio.events.type.EventContentType;
34  import info.bioinfweb.jphyloio.events.type.EventTopologyType;
35  import info.bioinfweb.jphyloio.formats.nexml.NeXMLEventReader;
36  import info.bioinfweb.jphyloio.utils.JPhyloIOReadingUtils;
37  import info.bioinfweb.treegraph.document.Document;
38  import info.bioinfweb.treegraph.document.HiddenDataMap;
39  import info.bioinfweb.treegraph.document.Node;
40  import info.bioinfweb.treegraph.document.TextElementData;
41  import info.bioinfweb.treegraph.document.Tree;
42  import info.bioinfweb.treegraph.document.io.AbstractDocumentReader;
43  import info.bioinfweb.treegraph.document.io.DocumentIterator;
44  import info.bioinfweb.treegraph.document.io.SingleDocumentIterator;
45  import info.bioinfweb.treegraph.document.nodebranchdata.BranchLengthAdapter;
46  import info.bioinfweb.treegraph.document.nodebranchdata.NodeBranchDataAdapter;
47  import info.bioinfweb.treegraph.document.nodebranchdata.NodeNameAdapter;
48 
49  import java.io.BufferedInputStream;
50  import java.io.IOException;
51  import java.util.ArrayList;
52  import java.util.HashMap;
53  import java.util.List;
54  import java.util.Map;
55 
56  import javax.xml.stream.XMLStreamException;
57 
58 
59 
60  public class NeXMLReader extends AbstractDocumentReader {
61      private JPhyloIOEventReader reader;
62      private String currentTreeName;
63      private List<Tree> trees = new ArrayList<Tree>();
64      private List<String> names = new ArrayList<String>();
65      private Map<String, Node> idToNodeMap = new HashMap<String, Node>();
66      private List<String> possiblePaintStartIDs = new ArrayList<String>();
67      private List<String> rootNodeIDs = new ArrayList<String>(); //TODO Mark all root nodes with icon label or something similar
68      private String currentColumnID = null;
69      private NodeBranchDataAdapter nodeNameAdapter = NodeNameAdapter.getSharedInstance();
70      private BranchLengthAdapter branchLengthAdapter = BranchLengthAdapter.getSharedInstance();
71      
72 
73      public NeXMLReader() {
74          super(false);
75      }
76 
77      
78      @Override
79      public Document readDocument(BufferedInputStream stream) throws Exception {
80          document = null;
81          ReadWriteParameterMap parameters = new ReadWriteParameterMap();
82          parameters.put(ReadWriteParameterMap.KEY_USE_OTU_LABEL, true);
83          reader = new NeXMLEventReader(stream, parameters);  //TODO Use JPhyloIOReader for other formats (currently not possible, due to exceptions)
84          
85          try {
86              JPhyloIOEvent event;
87              while (reader.hasNextEvent()) {
88            event = reader.next();
89            switch (event.getType().getContentType()) {
90              case DOCUMENT:
91                  if (event.getType().getTopologyType().equals(EventTopologyType.START)) {
92                      document = createEmptyDocument();
93                  }
94                  else if (event.getType().getTopologyType().equals(EventTopologyType.END)) {
95                    reader.close();
96                    
97                    if (!trees.isEmpty()) {
98                      Tree tree = trees.get(parameterMap.getTreeSelector().select(names.toArray(new String[names.size()]), trees));
99                      document.setTree(tree);
100                    }
101                    else {
102                      throw new IOException("The document did not contain any tree or no valid tree could be read from the document.");
103                    }
104                    
105                    return document;
106                  }
107                  break;
108              case TREE_NETWORK_GROUP:
109                  readTreeNetworkGroup(event.asLinkedLabeledIDEvent());
110                  break;
111              default:
112                  if (event.getType().getTopologyType().equals(EventTopologyType.START)) {  // Possible additional element, which is not read. SOLE and END events do not have to be processed here, because they have no further content.
113                      JPhyloIOReadingUtils.reachElementEnd(reader);
114                  }
115                  break;
116            }
117          }
118          }
119          finally {
120          reader.close();
121          stream.close();
122          }       
123          trees.clear();
124          return null;
125      }
126      
127      
128      private void readTreeNetworkGroup(LinkedLabeledIDEvent treeGroupEvent) throws XMLStreamException, IOException {
129      JPhyloIOEvent event = reader.next();   
130      while (!event.getType().getTopologyType().equals(EventTopologyType.END)) {
131          if (event.getType().getContentType().equals(EventContentType.TREE)) { // Networks can not be displayed by TG and are therefore not read         
132              readTree(event.asLabeledIDEvent());
133          }
134          else {  // Possible additional element, which is not read
135          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {  // SOLE and END events do not have to be processed here, because they have no further content.
136              JPhyloIOReadingUtils.reachElementEnd(reader);
137              }
138        }
139        event = reader.next();
140      }
141    }
142      
143      
144      private void readTree(LabeledIDEvent treeEvent) throws XMLStreamException, IOException {
145          if ((treeEvent.getLabel() != null) && !treeEvent.getLabel().isEmpty()) {
146              currentTreeName = treeEvent.getLabel();
147      }
148          else {
149              currentTreeName = treeEvent.getID();
150          }
151          
152          possiblePaintStartIDs.clear();
153          idToNodeMap.clear();
154          
155      JPhyloIOEvent event = reader.next();
156      while (!event.getType().getTopologyType().equals(EventTopologyType.END)) {      
157          if (event.getType().getContentType().equals(EventContentType.NODE)) {
158              readNode(event.asNodeEvent());
159          }
160          else if (event.getType().getContentType().equals(EventContentType.EDGE) || event.getType().getContentType().equals(EventContentType.ROOT_EDGE)) {
161              readEdge(event.asEdgeEvent());
162          }
163          else {  // Possible additional element, which is not read
164          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {  // SOLE and END events do not have to be processed here, because they have no further content.
165              JPhyloIOReadingUtils.reachElementEnd(reader);
166              }
167        }
168        event = reader.next();
169      }
170      
171      if (possiblePaintStartIDs.size() > 1) {
172          throw new IOException("More than one root node was found for the tree \"" + currentTreeName + "\", but this can not be displayed in TreeGraph 2.");
173      }
174      
175      Tree tree = new Tree();
176      tree.setPaintStart(idToNodeMap.get(possiblePaintStartIDs.get(0)));
177      tree.assignUniqueNames();
178      if (!rootNodeIDs.isEmpty()) {
179          tree.getFormats().setShowRooted(true);
180      }
181      trees.add(tree);
182      names.add(currentTreeName);    
183    }
184      
185      
186      private void readNode(NodeEvent nodeEvent) throws XMLStreamException, IOException {
187          Node node = Node.newInstanceWithBranch();
188 
189          nodeNameAdapter.setText(node, nodeEvent.getLabel());
190          idToNodeMap.put(nodeEvent.getID(), node);
191          possiblePaintStartIDs.add(nodeEvent.getID());
192          
193          if (nodeEvent.isRootNode()) {
194              rootNodeIDs.add(nodeEvent.getID());
195          }
196          
197          JPhyloIOEvent event = reader.next();
198      while (!event.getType().getTopologyType().equals(EventTopologyType.END)) {  // It is assumed that events are correctly nested
199          if (event.getType().getContentType().equals(EventContentType.LITERAL_META) || event.getType().getContentType().equals(EventContentType.RESOURCE_META)) {
200              readMetadata(event, node.getHiddenDataMap());
201          }
202          else if (event.getType().getContentType().equals(EventContentType.LITERAL_META_CONTENT)) {
203              readLiteralContent(event.asLiteralMetadataContentEvent(), node.getHiddenDataMap()); 
204          }
205        else {  // Possible additional element, which is not read
206          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {  // SOLE and END events do not have to be processed here, because they have no further content.
207              JPhyloIOReadingUtils.reachElementEnd(reader);
208              }
209        }
210        event = reader.next();
211      }
212    }
213      
214      
215      private void readEdge(EdgeEvent edgeEvent) throws XMLStreamException, IOException {
216          Node targetNode = idToNodeMap.get(edgeEvent.getTargetID());
217          Node sourceNode = idToNodeMap.get(edgeEvent.getSourceID());     
218          
219          if (targetNode.getParent() == null) {
220              targetNode.setParent(sourceNode);
221              branchLengthAdapter.setDecimal(targetNode, edgeEvent.getLength());
222              
223              if (sourceNode != null) {
224                  sourceNode.getChildren().add(targetNode);
225                  possiblePaintStartIDs.remove(edgeEvent.getTargetID());  // Nodes that were not referenced as target are possible paint starts
226              }
227          }
228          else {  // Edge is network edge
229              throw new IOException("Multiple parent nodes were specified for the node \"" + edgeEvent.getTargetID() + "\" in the tree \"" + currentTreeName 
230                      + "\", but networks can not be displayed by TreeGraph 2.");
231          }
232          
233          JPhyloIOEvent event = reader.next();
234      while (!event.getType().getTopologyType().equals(EventTopologyType.END)) {  // It is assumed that events are correctly nested
235          if (event.getType().getContentType().equals(EventContentType.LITERAL_META) || event.getType().getContentType().equals(EventContentType.RESOURCE_META)) {
236              readMetadata(event, targetNode.getAfferentBranch().getHiddenDataMap());
237          }
238          else if (event.getType().getContentType().equals(EventContentType.LITERAL_META_CONTENT)) {
239              readLiteralContent(event.asLiteralMetadataContentEvent(), targetNode.getAfferentBranch().getHiddenDataMap()); 
240          }
241          else {  // Possible additional element, which is not read
242          if (event.getType().getTopologyType().equals(EventTopologyType.START)) {  // SOLE and END events do not have to be processed here, because they have no further content.
243              JPhyloIOReadingUtils.reachElementEnd(reader);
244              }
245        }
246        event = reader.next();
247      }
248    }
249      
250      
251      private String extractMetadataKey(URIOrStringIdentifier predicate) {
252          return predicate.getURI().getNamespaceURI() + predicate.getURI().getLocalPart();
253          //TODO Extend functionality of this method when more formats are supported. (Make use of string representation alternatively.)
254          //TODO Will a '/' separating namespace URI and local part always be present/necessary? 
255      }
256      
257      
258      private void readMetadata(JPhyloIOEvent metaEvent, HiddenDataMap map) throws IOException {
259          if (metaEvent.getType().getTopologyType().equals(EventTopologyType.START)) {
260              if (metaEvent.getType().getContentType().equals(EventContentType.RESOURCE_META)) {
261                  ResourceMetadataEvent resourceMeta = metaEvent.asResourceMetadataEvent();
262                  if ((resourceMeta.getHRef() != null) && (resourceMeta.getRel().getURI() != null)) {
263                      storeMetaData(map, extractMetadataKey(resourceMeta.getRel()), new TextElementData(resourceMeta.getHRef().toString()));  // The whole predicate URI is used as a key here
264                  }
265              }
266              else if (metaEvent.getType().getContentType().equals(EventContentType.LITERAL_META)) {
267                  LiteralMetadataEvent literalMeta = metaEvent.asLiteralMetadataEvent();
268                  if (literalMeta.getPredicate().getURI() != null) {
269                      currentColumnID = extractMetadataKey(literalMeta.getPredicate());
270                  }
271              }
272          }
273          
274          JPhyloIOEvent event = reader.next();
275          while (!event.getType().getTopologyType().equals(EventTopologyType.END)) {
276              if (event.getType().getContentType().equals(EventContentType.LITERAL_META) || event.getType().getContentType().equals(EventContentType.RESOURCE_META)) {
277                  readMetadata(event, map);
278              }
279              else if (event.getType().getContentType().equals(EventContentType.LITERAL_META_CONTENT)) {
280                  readLiteralContent(event.asLiteralMetadataContentEvent(), map);
281              }
282              else {  // Possible additional element, which is not read
283              if (event.getType().getTopologyType().equals(EventTopologyType.START)) {  // SOLE and END events do not have to be processed here, because they have no further content.
284                  JPhyloIOReadingUtils.reachElementEnd(reader);
285                  }
286            }
287            event = reader.next();
288          }
289      }
290      
291      
292      private void readLiteralContent(LiteralMetadataContentEvent literalEvent, HiddenDataMap map) throws IOException {
293          StringBuffer content = new StringBuffer();
294          TextElementData data = null;
295          
296          if (literalEvent.getObjectValue() != null) {
297              if (literalEvent.getObjectValue() instanceof Number) {
298                  data = new TextElementData(((Number)literalEvent.getObjectValue()).doubleValue());
299              }
300              else {
301                  content.append(literalEvent.getObjectValue().toString());         
302              }
303      }
304      else {
305          content.append(literalEvent.getStringValue());
306      }
307          
308          JPhyloIOEvent event = reader.peek();
309      while (event.getType().getContentType().equals(EventContentType.LITERAL_META_CONTENT)) {        
310        event = reader.next();
311        content.append(event.asLiteralMetadataContentEvent().getStringValue());  // Content can only be continued if it has only a string value      
312      }
313      
314      if (data == null) {
315          data = new TextElementData(content.toString());
316      }
317          
318      storeMetaData(map, currentColumnID, data);
319      }
320      
321      
322      private void storeMetaData(HiddenDataMap map, String key, TextElementData data) {
323          if (!map.containsKey(key)) {
324              map.put(key, data);
325          }
326          else {
327              parameterMap.getApplicationLogger().addMessage("More than one value with the key \"" + currentColumnID + "\" was encountered for one node or branch."
328                      + " Only the first encountered value was imported.");
329          }
330      }
331      
332 
333      @Override
334      public DocumentIterator createIterator(BufferedInputStream stream) throws Exception {
335          return new SingleDocumentIterator(read(stream));
336      }
337  }


feed icon

sventon 2.5.1

Valid XHTML 1.0 Strict   CSS ist valide!
TreeGraph icon
bioinfweb RSS feed TreeGraph 2 on ResearchGate bioinfweb on twitter TreeGraph 2 on GitHub
bioinfweb - Biology & Informatics Website