MyFileSourceGraphML.java 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654
  1. /*This is a modified version of the class org.graphstream.stream.file.FileSourceGraphML
  2. * It was modified by Jascha Bohne <jaschabohne@web.de> for use in the scopviz project
  3. *
  4. * Copyright 2006 - 2015
  5. * Stefan Balev <stefan.balev@graphstream-project.org>
  6. * Julien Baudry <julien.baudry@graphstream-project.org>
  7. * Antoine Dutot <antoine.dutot@graphstream-project.org>
  8. * Yoann Pigné <yoann.pigne@graphstream-project.org>
  9. * Guilhelm Savin <guilhelm.savin@graphstream-project.org>
  10. *
  11. * This file is part of GraphStream <http://graphstream-project.org>.
  12. *
  13. * GraphStream is a library whose purpose is to handle static or dynamic
  14. * graph, create them from scratch, file or any source and display them.
  15. *
  16. * This program is free software distributed under the terms of two licenses, the
  17. * CeCILL-C license that fits European law, and the GNU Lesser General Public
  18. * License. You can use, modify and/ or redistribute the software under the terms
  19. * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
  20. * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
  21. * the Free Software Foundation, either version 3 of the License, or (at your
  22. * option) any later version.
  23. *
  24. * This program is distributed in the hope that it will be useful, but WITHOUT ANY
  25. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  26. * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
  27. *
  28. * You should have received a copy of the GNU Lesser General Public License
  29. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  30. *
  31. * The fact that you are presently reading this means that you have had
  32. * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
  33. */
  34. package de.tu_darmstadt.informatik.tk.scopviz.io;
  35. import java.io.FileReader;
  36. import java.io.IOException;
  37. import java.io.InputStream;
  38. import java.io.InputStreamReader;
  39. import java.io.Reader;
  40. import java.net.URL;
  41. import java.util.HashMap;
  42. import java.util.HashSet;
  43. import java.util.Iterator;
  44. import java.util.LinkedList;
  45. import java.util.Stack;
  46. import javax.xml.stream.FactoryConfigurationError;
  47. import javax.xml.stream.Location;
  48. import javax.xml.stream.XMLEventReader;
  49. import javax.xml.stream.XMLInputFactory;
  50. import javax.xml.stream.XMLStreamConstants;
  51. import javax.xml.stream.XMLStreamException;
  52. import javax.xml.stream.events.Attribute;
  53. import javax.xml.stream.events.XMLEvent;
  54. import org.graphstream.stream.file.FileSource;
  55. import de.tu_darmstadt.informatik.tk.scopviz.debug.Debug;
  56. import de.tu_darmstadt.informatik.tk.scopviz.io.MyFileSourceGraphML.NodeAttribute.EndPointType;
  57. /**
  58. * GraphML is a comprehensive and easy-to-use file format for graphs. It
  59. * consists of a language core to describe the structural properties of a graph
  60. * and a flexible extension mechanism to add application-specific data. Its main
  61. * features include support of
  62. * <ul>
  63. * <li>directed, undirected, and mixed graphs,</li>
  64. * <li>hypergraphs,</li>
  65. * <li>hierarchical graphs,</li>
  66. * <li>graphical representations,</li>
  67. * <li>references to external data,</li>
  68. * <li>application-specific attribute data, and</li>
  69. * <li>light-weight parsers.</li>
  70. * </ul>
  71. *
  72. * Unlike many other file formats for graphs, GraphML does not use a custom
  73. * syntax. Instead, it is based on XML and hence ideally suited as a common
  74. * denominator for all kinds of services generating, archiving, or processing
  75. * graphs.
  76. *
  77. * <a href="http://graphml.graphdrawing.org/index.html">Source</a>
  78. */
  79. public class MyFileSourceGraphML extends MySourceBase implements FileSource, XMLStreamConstants {
  80. /**
  81. * An Enum of the various States the reader can be in.
  82. */
  83. protected enum ReaderState {
  84. START, DESC, KEYS, NEW_GRAPH, NODES_EDGES, GRAPH_END, END
  85. }
  86. /**
  87. * The currently held Reader state.
  88. */
  89. private ReaderState currentReaderState = ReaderState.START;
  90. protected enum Balise {
  91. GRAPHML, GRAPH, NODE, EDGE, HYPEREDGE, DESC, DATA, LOCATOR, PORT, KEY, DEFAULT
  92. }
  93. protected enum GraphAttribute {
  94. ID, EDGEDEFAULT
  95. }
  96. protected enum LocatorAttribute {
  97. XMLNS_XLINK, XLINK_HREF, XLINK_TYPE
  98. }
  99. protected enum NodeAttribute {
  100. ID;
  101. protected enum EndPointType {
  102. IN, OUT, UNDIR
  103. }
  104. }
  105. protected enum EdgeAttribute {
  106. ID, SOURCE, SOURCEPORT, TARGET, TARGETPORT, DIRECTED
  107. }
  108. protected enum DataAttribute {
  109. KEY, ID
  110. }
  111. protected enum PortAttribute {
  112. NAME
  113. }
  114. protected enum EndPointAttribute {
  115. ID, NODE, PORT, TYPE
  116. }
  117. protected enum HyperEdgeAttribute {
  118. ID
  119. }
  120. protected enum KeyAttribute {
  121. ID, FOR, ATTR_NAME, ATTR_TYPE, YFILES_TYPE
  122. }
  123. protected enum KeyDomain {
  124. GRAPHML, GRAPH, NODE, EDGE, HYPEREDGE, PORT, ENDPOINT, ALL
  125. }
  126. protected enum KeyAttrType {
  127. BOOLEAN, INT, LONG, FLOAT, DOUBLE, STRING
  128. }
  129. protected static class Key {
  130. KeyDomain domain;
  131. String name;
  132. KeyAttrType type;
  133. String def = null;
  134. Key() {
  135. domain = KeyDomain.ALL;
  136. name = null;
  137. type = KeyAttrType.STRING;
  138. }
  139. Object getKeyValue(String value) {
  140. if (value == null)
  141. return null;
  142. switch (type) {
  143. case STRING:
  144. return value;
  145. case INT:
  146. return Integer.valueOf(value);
  147. case LONG:
  148. return Long.valueOf(value);
  149. case FLOAT:
  150. return Float.valueOf(value);
  151. case DOUBLE:
  152. return Double.valueOf(value);
  153. case BOOLEAN:
  154. return Boolean.valueOf(value);
  155. }
  156. return value;
  157. }
  158. Object getDefaultValue() {
  159. return getKeyValue(def);
  160. }
  161. }
  162. protected static class Data {
  163. Key key;
  164. String id;
  165. String value;
  166. }
  167. protected static class Locator {
  168. String href;
  169. String xlink;
  170. String type;
  171. Locator() {
  172. xlink = "http://www.w3.org/TR/2000/PR-xlink-20001220/";
  173. type = "simple";
  174. href = null;
  175. }
  176. }
  177. protected static class Port {
  178. String name;
  179. String desc;
  180. LinkedList<Data> datas;
  181. LinkedList<Port> ports;
  182. Port() {
  183. name = null;
  184. desc = null;
  185. datas = new LinkedList<Data>();
  186. ports = new LinkedList<Port>();
  187. }
  188. }
  189. protected static class EndPoint {
  190. String id;
  191. String node;
  192. String port;
  193. String desc;
  194. EndPointType type;
  195. EndPoint() {
  196. id = null;
  197. node = null;
  198. port = null;
  199. desc = null;
  200. type = EndPointType.UNDIR;
  201. }
  202. }
  203. protected XMLEventReader reader;
  204. protected HashMap<String, Key> keys;
  205. protected LinkedList<Data> datas;
  206. protected Stack<XMLEvent> events;
  207. protected Stack<String> graphId;
  208. protected int graphCounter;
  209. protected boolean edgeDefault;
  210. protected Data yPosition = null;
  211. /**
  212. * Build a new source to parse an xml stream in GraphML format.
  213. */
  214. public MyFileSourceGraphML() {
  215. init();
  216. }
  217. private void init() {
  218. events = new Stack<XMLEvent>();
  219. keys = new HashMap<String, Key>();
  220. datas = new LinkedList<Data>();
  221. graphId = new Stack<String>();
  222. graphCounter = 0;
  223. sourceId = String.format("<GraphML stream %x>", System.nanoTime());
  224. }
  225. /*
  226. * (non-Javadoc)
  227. *
  228. * @see org.graphstream.stream.file.FileSource#readAll(java.lang.String)
  229. */
  230. public void readAll(String fileName) throws IOException {
  231. readAll(new FileReader(fileName));
  232. }
  233. /*
  234. * (non-Javadoc)
  235. *
  236. * @see org.graphstream.stream.file.FileSource#readAll(java.net.URL)
  237. */
  238. public void readAll(URL url) throws IOException {
  239. readAll(url.openStream());
  240. }
  241. /*
  242. * (non-Javadoc)
  243. *
  244. * @see org.graphstream.stream.file.FileSource#readAll(java.io.InputStream)
  245. */
  246. public void readAll(InputStream stream) throws IOException {
  247. readAll(new InputStreamReader(stream));
  248. }
  249. /*
  250. * (non-Javadoc)
  251. *
  252. * @see org.graphstream.stream.file.FileSource#readAll(java.io.Reader)
  253. */
  254. public void readAll(Reader reader) throws IOException {
  255. begin(reader);
  256. while (nextEvents())
  257. ;
  258. end();
  259. }
  260. /*
  261. * (non-Javadoc)
  262. *
  263. * @see org.graphstream.stream.file.FileSource#begin(java.lang.String)
  264. */
  265. public void begin(String fileName) throws IOException {
  266. begin(new FileReader(fileName));
  267. }
  268. /*
  269. * (non-Javadoc)
  270. *
  271. * @see org.graphstream.stream.file.FileSource#begin(java.net.URL)
  272. */
  273. public void begin(URL url) throws IOException {
  274. begin(url.openStream());
  275. }
  276. /*
  277. * (non-Javadoc)
  278. *
  279. * @see org.graphstream.stream.file.FileSource#begin(java.io.InputStream)
  280. */
  281. public void begin(InputStream stream) throws IOException {
  282. begin(new InputStreamReader(stream));
  283. }
  284. /*
  285. * (non-Javadoc)
  286. *
  287. * @see org.graphstream.stream.file.FileSource#begin(java.io.Reader)
  288. */
  289. public void begin(Reader reader) throws IOException {
  290. openStream(reader);
  291. }
  292. /*
  293. * (non-Javadoc)
  294. *
  295. * @see org.graphstream.stream.file.FileSource#nextEvents()
  296. */
  297. public boolean nextEvents() throws IOException {
  298. try {
  299. __graphml();
  300. } catch (XMLStreamException ex) {
  301. throw new IOException(ex);
  302. }
  303. return false;
  304. }
  305. /*
  306. * (non-Javadoc)
  307. *
  308. * @see org.graphstream.stream.file.FileSource#nextStep()
  309. */
  310. public boolean nextStep() throws IOException {
  311. return nextEvents();
  312. }
  313. /*
  314. * (non-Javadoc)
  315. *
  316. * @see org.graphstream.stream.file.FileSource#end()
  317. */
  318. public void end() throws IOException {
  319. closeStream();
  320. }
  321. protected XMLEvent getNextEvent() throws IOException, XMLStreamException {
  322. skipWhiteSpaces();
  323. XMLEvent temp;
  324. if (events.size() > 0)
  325. temp = events.pop();
  326. else {
  327. temp = reader.nextEvent();
  328. }
  329. if (temp.getEventType() == XMLEvent.COMMENT) {
  330. temp = getNextEvent();
  331. }
  332. return temp;
  333. }
  334. protected void pushback(XMLEvent e) {
  335. events.push(e);
  336. }
  337. private XMLStreamException newParseError(XMLEvent e, String msg, Object... args) {
  338. return new XMLStreamException(String.format(msg, args), e.getLocation());
  339. }
  340. private boolean isEvent(XMLEvent e, int type, String name) {
  341. boolean valid = e.getEventType() == type;
  342. if (valid) {
  343. switch (type) {
  344. case START_ELEMENT:
  345. valid = e.asStartElement().getName().getLocalPart().equals(name);
  346. break;
  347. case END_ELEMENT:
  348. valid = e.asEndElement().getName().getLocalPart().equals(name);
  349. break;
  350. case ATTRIBUTE:
  351. valid = ((Attribute) e).getName().getLocalPart().equals(name);
  352. break;
  353. case CHARACTERS:
  354. case NAMESPACE:
  355. case PROCESSING_INSTRUCTION:
  356. case START_DOCUMENT:
  357. case END_DOCUMENT:
  358. case DTD:
  359. }
  360. }
  361. return valid;
  362. }
  363. private void checkValid(XMLEvent e, int type, String name) throws XMLStreamException {
  364. boolean valid = isEvent(e, type, name);
  365. if (!valid)
  366. throw newParseError(e, "expecting %s, got %s", gotWhat(type, name), gotWhat(e));
  367. }
  368. private String gotWhat(XMLEvent e) {
  369. String v = null;
  370. switch (e.getEventType()) {
  371. case START_ELEMENT:
  372. v = e.asStartElement().getName().getLocalPart();
  373. break;
  374. case END_ELEMENT:
  375. v = e.asEndElement().getName().getLocalPart();
  376. break;
  377. case ATTRIBUTE:
  378. v = ((Attribute) e).getName().getLocalPart();
  379. break;
  380. }
  381. return gotWhat(e.getEventType(), v);
  382. }
  383. public String gotWhat(int type, String v) {
  384. switch (type) {
  385. case START_ELEMENT:
  386. return String.format("'<%s>'", v);
  387. case END_ELEMENT:
  388. return String.format("'</%s>'", v);
  389. case ATTRIBUTE:
  390. return String.format("attribute '%s'", v);
  391. case NAMESPACE:
  392. return "namespace";
  393. case PROCESSING_INSTRUCTION:
  394. return "processing instruction";
  395. case COMMENT:
  396. return "comment";
  397. case START_DOCUMENT:
  398. return "document start";
  399. case END_DOCUMENT:
  400. return "document end";
  401. case DTD:
  402. return "dtd";
  403. case CHARACTERS:
  404. return "characters";
  405. default:
  406. return "UNKNOWN";
  407. }
  408. }
  409. private Object getValue(Data data) {
  410. switch (data.key.type) {
  411. case BOOLEAN:
  412. if (data.value == null || data.value.equals(""))
  413. return false;
  414. return Boolean.parseBoolean(data.value);
  415. case INT:
  416. if (data.value == null || data.value.equals(""))
  417. return new Integer(0);
  418. return Integer.parseInt(data.value);
  419. case LONG:
  420. if (data.value == null || data.value.equals(""))
  421. return new Long(0);
  422. return Long.parseLong(data.value);
  423. case FLOAT:
  424. if (data.value == null || data.value.equals(""))
  425. return new Float(0);
  426. return Float.parseFloat(data.value);
  427. case DOUBLE:
  428. if (data.value == null || data.value.equals(""))
  429. return new Double(0);
  430. Debug.out(data.value);
  431. return Double.parseDouble(data.value);
  432. case STRING:
  433. return data.value;
  434. }
  435. return data.value;
  436. }
  437. private Object getDefaultValue(Key key) {
  438. switch (key.type) {
  439. case BOOLEAN:
  440. return Boolean.TRUE;
  441. case INT:
  442. if (key.def != null)
  443. return Integer.valueOf(key.def);
  444. return Integer.valueOf(0);
  445. case LONG:
  446. if (key.def != null)
  447. return Long.valueOf(key.def);
  448. return Long.valueOf(0);
  449. case FLOAT:
  450. if (key.def != null)
  451. return Float.valueOf(key.def);
  452. return Float.valueOf(0.0f);
  453. case DOUBLE:
  454. if (key.def != null)
  455. return Double.valueOf(key.def);
  456. return Double.valueOf(0.0);
  457. case STRING:
  458. if (key.def != null)
  459. return key.def;
  460. return "";
  461. }
  462. return key.def != null ? key.def : Boolean.TRUE;
  463. }
  464. private void skipWhiteSpaces() throws IOException, XMLStreamException {
  465. XMLEvent e;
  466. do {
  467. if (events.size() > 0)
  468. e = events.pop();
  469. else
  470. e = reader.nextEvent();
  471. } while (isEvent(e, XMLEvent.CHARACTERS, null) && e.asCharacters().getData().matches("^\\s*$"));
  472. pushback(e);
  473. }
  474. protected void openStream(Reader stream) throws IOException {
  475. if (reader != null)
  476. closeStream();
  477. try {
  478. XMLEvent e;
  479. reader = XMLInputFactory.newInstance().createXMLEventReader(stream);
  480. e = getNextEvent();
  481. checkValid(e, XMLEvent.START_DOCUMENT, null);
  482. } catch (XMLStreamException e) {
  483. throw new IOException(e);
  484. } catch (FactoryConfigurationError e) {
  485. throw new IOException(e);
  486. }
  487. }
  488. protected void closeStream() throws IOException {
  489. try {
  490. reader.close();
  491. } catch (XMLStreamException e) {
  492. throw new IOException(e);
  493. } finally {
  494. reader = null;
  495. }
  496. }
  497. protected String toConstantName(Attribute a) {
  498. return toConstantName(a.getName().getLocalPart());
  499. }
  500. protected String toConstantName(String value) {
  501. return value.toUpperCase().replaceAll("\\W", "_");
  502. }
  503. // TODO: handle malformed files on state switches
  504. /**
  505. * parses a Stream of xml Events to a graphstream graph it has limited
  506. * support for yEd attributes
  507. *
  508. * @throws IOException
  509. * @throws XMLStreamException
  510. */
  511. private void __graphml() throws IOException, XMLStreamException {
  512. XMLEvent e;
  513. e = getNextEvent();
  514. // reading the file
  515. while (true) {
  516. switch (currentReaderState) {
  517. case START:
  518. checkValid(e, XMLEvent.START_ELEMENT, "graphml");
  519. currentReaderState = ReaderState.DESC;
  520. e = getNextEvent();
  521. break;
  522. case DESC:
  523. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  524. pushback(e);
  525. __desc();
  526. e = getNextEvent();
  527. } else {
  528. currentReaderState = ReaderState.KEYS;
  529. }
  530. break;
  531. case KEYS:
  532. if (isEvent(e, XMLEvent.START_ELEMENT, "key")) {
  533. pushback(e);
  534. __key();
  535. e = getNextEvent();
  536. } else {
  537. currentReaderState = ReaderState.NEW_GRAPH;
  538. }
  539. break;
  540. case NEW_GRAPH:
  541. if (isEvent(e, XMLEvent.START_ELEMENT, "graph")) {
  542. newSubGraph();
  543. pushback(e);
  544. __graph();
  545. e = getNextEvent();
  546. }
  547. if (isEvent(e, XMLEvent.START_ELEMENT, "node") || isEvent(e, XMLEvent.START_ELEMENT, "edge")) {
  548. currentReaderState = ReaderState.NODES_EDGES;
  549. } else if (isEvent(e, XMLEvent.END_ELEMENT, "graph")) {
  550. currentReaderState = ReaderState.GRAPH_END;
  551. } else if (isEvent(e, XMLEvent.START_ELEMENT, "data")) {
  552. // <data> is ignored
  553. pushback(e);
  554. __data();
  555. e = getNextEvent();
  556. } else {
  557. throw newParseError(e, "expecting %s, got %s", "<graph>, </graph>, <node>, <edge> or <data>",
  558. gotWhat(e));
  559. }
  560. break;
  561. case NODES_EDGES:
  562. pushback(e);
  563. if (isEvent(e, XMLEvent.START_ELEMENT, "node")) {
  564. __node();
  565. e = getNextEvent();
  566. } else if (isEvent(e, XMLEvent.START_ELEMENT, "edge")) {
  567. __edge(edgeDefault);
  568. e = getNextEvent();
  569. } else if (isEvent(e, XMLEvent.END_ELEMENT, "graph")) {
  570. currentReaderState = ReaderState.GRAPH_END;
  571. e = getNextEvent();
  572. } else if (isEvent(e, XMLEvent.END_ELEMENT, "graphml")) {
  573. currentReaderState = ReaderState.END;
  574. e = getNextEvent();
  575. } else if (isEvent(e, XMLEvent.START_ELEMENT, "data")) {
  576. datas.add(__data());
  577. e = getNextEvent();
  578. } else if (isEvent(e, XMLEvent.START_ELEMENT, "hyperedge")) {
  579. __hyperedge();
  580. e = getNextEvent();
  581. } else {
  582. throw newParseError(e, "expecting %s, got %s", "</graph>, <node> or <edge>", gotWhat(e));
  583. }
  584. break;
  585. case GRAPH_END:
  586. if (isEvent(e, END_ELEMENT, "graph")) {
  587. e = getNextEvent();
  588. subGraphFinished();
  589. }
  590. if (isEvent(e, XMLEvent.START_ELEMENT, "graph")) {
  591. currentReaderState = ReaderState.NEW_GRAPH;
  592. } else if (isEvent(e, XMLEvent.END_ELEMENT, "graphml")) {
  593. currentReaderState = ReaderState.END;
  594. } else if (isEvent(e, XMLEvent.START_ELEMENT, "key")) {
  595. currentReaderState = ReaderState.KEYS;
  596. } else if (isEvent(e, XMLEvent.START_ELEMENT, "node") || isEvent(e, XMLEvent.START_ELEMENT, "edge")) {
  597. currentReaderState = ReaderState.NODES_EDGES;
  598. } else if (isEvent(e, XMLEvent.START_ELEMENT, "data")) {
  599. // ignore <data>
  600. pushback(e);
  601. __data();
  602. e = getNextEvent();
  603. } else {
  604. throw newParseError(e, "expecting %s, got %s", "<data>, <graph>, </graphml> or <key>", gotWhat(e));
  605. }
  606. break;
  607. case END:
  608. currentReaderState = ReaderState.START;
  609. init();
  610. return;
  611. }
  612. }
  613. }
  614. private String __characters() throws IOException, XMLStreamException {
  615. XMLEvent e;
  616. StringBuilder buffer = new StringBuilder();
  617. e = getNextEvent();
  618. while (e.getEventType() == XMLEvent.CHARACTERS) {
  619. buffer.append(e.asCharacters());
  620. e = getNextEvent();
  621. }
  622. pushback(e);
  623. return buffer.toString();
  624. }
  625. /**
  626. * <pre>
  627. * <!ELEMENT desc (#PCDATA)>
  628. * </pre>
  629. *
  630. * @return
  631. * @throws IOException
  632. * @throws XMLStreamException
  633. */
  634. private String __desc() throws IOException, XMLStreamException {
  635. XMLEvent e;
  636. String desc;
  637. e = getNextEvent();
  638. checkValid(e, XMLEvent.START_ELEMENT, "desc");
  639. desc = __characters();
  640. e = getNextEvent();
  641. checkValid(e, XMLEvent.END_ELEMENT, "desc");
  642. return desc;
  643. }
  644. /**
  645. * <pre>
  646. * <!ELEMENT locator EMPTY>
  647. * <!ATTLIST locator
  648. * xmlns:xlink CDATA #FIXED "http://www.w3.org/TR/2000/PR-xlink-20001220/"
  649. * xlink:href CDATA #REQUIRED
  650. * xlink:type (simple) #FIXED "simple"
  651. * >
  652. * </pre>
  653. *
  654. * @return
  655. * @throws IOException
  656. * @throws XMLStreamException
  657. */
  658. private Locator __locator() throws IOException, XMLStreamException {
  659. XMLEvent e;
  660. e = getNextEvent();
  661. checkValid(e, XMLEvent.START_ELEMENT, "locator");
  662. @SuppressWarnings("unchecked")
  663. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  664. Locator loc = new Locator();
  665. while (attributes.hasNext()) {
  666. Attribute a = attributes.next();
  667. try {
  668. LocatorAttribute attribute = LocatorAttribute.valueOf(toConstantName(a));
  669. switch (attribute) {
  670. case XMLNS_XLINK:
  671. loc.xlink = a.getValue();
  672. break;
  673. case XLINK_HREF:
  674. loc.href = a.getValue();
  675. break;
  676. case XLINK_TYPE:
  677. loc.type = a.getValue();
  678. break;
  679. }
  680. } catch (IllegalArgumentException ex) {
  681. throw newParseError(e, "invalid locator attribute '%s'", a.getName().getLocalPart());
  682. }
  683. }
  684. e = getNextEvent();
  685. checkValid(e, XMLEvent.END_ELEMENT, "locator");
  686. if (loc.href == null)
  687. throw newParseError(e, "locator requires an href");
  688. return loc;
  689. }
  690. /**
  691. * <pre>
  692. * <!ELEMENT key (#PCDATA)>
  693. * <!ATTLIST key
  694. * id ID #REQUIRED
  695. * for (graphml|graph|node|edge|hyperedge|port|endpoint|all) "all"
  696. * >
  697. * </pre>
  698. *
  699. * @throws IOException
  700. * @throws XMLStreamException
  701. */
  702. private void __key() throws IOException, XMLStreamException {
  703. XMLEvent e;
  704. e = getNextEvent();
  705. checkValid(e, XMLEvent.START_ELEMENT, "key");
  706. @SuppressWarnings("unchecked")
  707. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  708. String id = null;
  709. KeyDomain domain = KeyDomain.ALL;
  710. KeyAttrType type = KeyAttrType.STRING;
  711. String name = null;
  712. String def = null;
  713. while (attributes.hasNext()) {
  714. Attribute a = attributes.next();
  715. try {
  716. KeyAttribute attribute = KeyAttribute.valueOf(toConstantName(a));
  717. switch (attribute) {
  718. case ID:
  719. id = a.getValue();
  720. break;
  721. case FOR:
  722. try {
  723. domain = KeyDomain.valueOf(toConstantName(a.getValue()));
  724. } catch (IllegalArgumentException ex) {
  725. throw newParseError(e, "invalid key domain '%s'", a.getValue());
  726. }
  727. break;
  728. case ATTR_TYPE:
  729. try {
  730. type = KeyAttrType.valueOf(toConstantName(a.getValue()));
  731. } catch (IllegalArgumentException ex) {
  732. throw newParseError(e, "invalid key type '%s'", a.getValue());
  733. }
  734. break;
  735. case ATTR_NAME:
  736. name = a.getValue();
  737. break;
  738. case YFILES_TYPE:
  739. break;
  740. }
  741. } catch (IllegalArgumentException ex) {
  742. throw newParseError(e, "invalid key attribute '%s'", a.getName().getLocalPart());
  743. }
  744. }
  745. e = getNextEvent();
  746. if (isEvent(e, XMLEvent.START_ELEMENT, "default")) {
  747. def = __characters();
  748. e = getNextEvent();
  749. checkValid(e, XMLEvent.END_ELEMENT, "default");
  750. e = getNextEvent();
  751. }
  752. checkValid(e, XMLEvent.END_ELEMENT, "key");
  753. if (id == null)
  754. throw newParseError(e, "key requires an id");
  755. if (name == null)
  756. name = id;
  757. Debug.out("add key \"" + id + "\"");
  758. Key k = new Key();
  759. k.name = name;
  760. k.domain = domain;
  761. k.type = type;
  762. k.def = def;
  763. keys.put(id, k);
  764. }
  765. /**
  766. * <pre>
  767. * <!ELEMENT port ((desc)?,((data)|(port))*)>
  768. * <!ATTLIST port
  769. * name NMTOKEN #REQUIRED
  770. * >
  771. * </pre>
  772. *
  773. * @return
  774. * @throws IOException
  775. * @throws XMLStreamException
  776. */
  777. private Port __port() throws IOException, XMLStreamException {
  778. XMLEvent e;
  779. e = getNextEvent();
  780. checkValid(e, XMLEvent.START_ELEMENT, "port");
  781. Port port = new Port();
  782. @SuppressWarnings("unchecked")
  783. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  784. while (attributes.hasNext()) {
  785. Attribute a = attributes.next();
  786. try {
  787. PortAttribute attribute = PortAttribute.valueOf(toConstantName(a));
  788. switch (attribute) {
  789. case NAME:
  790. port.name = a.getValue();
  791. break;
  792. }
  793. } catch (IllegalArgumentException ex) {
  794. throw newParseError(e, "invalid attribute '%s' for '<port>'", a.getName().getLocalPart());
  795. }
  796. }
  797. if (port.name == null)
  798. throw newParseError(e, "'<port>' element requires a 'name' attribute");
  799. e = getNextEvent();
  800. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  801. pushback(e);
  802. port.desc = __desc();
  803. } else {
  804. while (isEvent(e, XMLEvent.START_ELEMENT, "data") || isEvent(e, XMLEvent.START_ELEMENT, "port")) {
  805. if (isEvent(e, XMLEvent.START_ELEMENT, "data")) {
  806. Data data;
  807. pushback(e);
  808. data = __data();
  809. port.datas.add(data);
  810. } else {
  811. Port portChild;
  812. pushback(e);
  813. portChild = __port();
  814. port.ports.add(portChild);
  815. }
  816. e = getNextEvent();
  817. }
  818. }
  819. e = getNextEvent();
  820. checkValid(e, XMLEvent.END_ELEMENT, "port");
  821. return port;
  822. }
  823. /**
  824. * <pre>
  825. * <!ELEMENT endpoint ((desc)?)>
  826. * <!ATTLIST endpoint
  827. * id ID #IMPLIED
  828. * node IDREF #REQUIRED
  829. * port NMTOKEN #IMPLIED
  830. * type (in|out|undir) "undir"
  831. * >
  832. * </pre>
  833. *
  834. * @return
  835. * @throws IOException
  836. * @throws XMLStreamException
  837. */
  838. private EndPoint __endpoint() throws IOException, XMLStreamException {
  839. XMLEvent e;
  840. e = getNextEvent();
  841. checkValid(e, XMLEvent.START_ELEMENT, "endpoint");
  842. @SuppressWarnings("unchecked")
  843. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  844. EndPoint ep = new EndPoint();
  845. while (attributes.hasNext()) {
  846. Attribute a = attributes.next();
  847. try {
  848. EndPointAttribute attribute = EndPointAttribute.valueOf(toConstantName(a));
  849. switch (attribute) {
  850. case NODE:
  851. ep.node = a.getValue();
  852. break;
  853. case ID:
  854. ep.id = a.getValue();
  855. break;
  856. case PORT:
  857. ep.port = a.getValue();
  858. break;
  859. case TYPE:
  860. try {
  861. ep.type = EndPointType.valueOf(toConstantName(a.getValue()));
  862. } catch (IllegalArgumentException ex) {
  863. throw newParseError(e, "invalid end point type '%s'", a.getValue());
  864. }
  865. break;
  866. }
  867. } catch (IllegalArgumentException ex) {
  868. throw newParseError(e, "invalid attribute '%s' for '<endpoint>'", a.getName().getLocalPart());
  869. }
  870. }
  871. if (ep.node == null)
  872. throw newParseError(e, "'<endpoint>' element requires a 'node' attribute");
  873. e = getNextEvent();
  874. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  875. pushback(e);
  876. ep.desc = __desc();
  877. }
  878. e = getNextEvent();
  879. checkValid(e, XMLEvent.END_ELEMENT, "endpoint");
  880. return ep;
  881. }
  882. /**
  883. * <pre>
  884. * <!ELEMENT data (#PCDATA)>
  885. * <!ATTLIST data
  886. * key IDREF #REQUIRED
  887. * id ID #IMPLIED
  888. * >
  889. * </pre>
  890. *
  891. * @return
  892. * @throws IOException
  893. * @throws XMLStreamException
  894. */
  895. private Data __data() throws IOException, XMLStreamException {
  896. XMLEvent e;
  897. StringBuilder buffer = new StringBuilder();
  898. e = getNextEvent();
  899. checkValid(e, XMLEvent.START_ELEMENT, "data");
  900. @SuppressWarnings("unchecked")
  901. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  902. String key = null, id = null;
  903. while (attributes.hasNext()) {
  904. Attribute a = attributes.next();
  905. try {
  906. DataAttribute attribute = DataAttribute.valueOf(toConstantName(a));
  907. switch (attribute) {
  908. case KEY:
  909. key = a.getValue();
  910. break;
  911. case ID:
  912. id = a.getValue();
  913. break;
  914. }
  915. } catch (IllegalArgumentException ex) {
  916. throw newParseError(e, "invalid attribute '%s' for '<data>'", a.getName().getLocalPart());
  917. }
  918. }
  919. if (key == null)
  920. throw newParseError(e, "'<data>' element must have a 'key' attribute");
  921. e = getNextEvent();
  922. while (e.getEventType() == XMLEvent.CHARACTERS) {
  923. buffer.append(e.asCharacters());
  924. e = getNextEvent();
  925. }
  926. if (e.isStartElement() && e.asStartElement().getName().getPrefix() == "y") {
  927. pushback(e);
  928. parseYed();
  929. e = getNextEvent();
  930. }
  931. checkValid(e, XMLEvent.END_ELEMENT, "data");
  932. if (keys.containsKey(key))
  933. newParseError(e, "unknown key '%s'", key);
  934. Data d = new Data();
  935. d.key = keys.get(key);
  936. d.id = id;
  937. d.value = buffer.toString();
  938. return d;
  939. }
  940. // TODO color parsing
  941. /**
  942. * Parses a yEdattribute. returns null if the Attribute is unknown.
  943. *
  944. * The known Attributes are:
  945. * <li>position of nodes</li>
  946. * <li>The label of Nodes</li>
  947. * <li>color of nodes</li>
  948. *
  949. * @return the parsed yEd Attribute as a Data object
  950. * @throws IOException
  951. * @throws XMLStreamException
  952. */
  953. private Data parseYed() throws IOException, XMLStreamException {
  954. XMLEvent e = getNextEvent();
  955. String name = null;
  956. if (e.getEventType() == START_ELEMENT) {
  957. name = e.asStartElement().getName().getLocalPart();
  958. } else if (e.getEventType() == END_ELEMENT) {
  959. name = e.asEndElement().getName().getLocalPart();
  960. } else {
  961. newParseError(e, "expected XMLEvent.START_ELEMENT or XMLEvent.END_ELEMENT, got neither", "");
  962. }
  963. // converting yed attributes
  964. Data data = null;
  965. Key k = null;
  966. switch (name) {
  967. // TODO weight
  968. case "Geometry":
  969. // the coordinates
  970. yPosition = new Data();
  971. k = new Key();
  972. k.def = null;
  973. k.domain = KeyDomain.ALL;
  974. k.name = "yEd.y";
  975. k.type = KeyAttrType.DOUBLE;
  976. yPosition.key = k;
  977. data = new Data();
  978. k = new Key();
  979. k.def = null;
  980. k.domain = KeyDomain.ALL;
  981. k.name = "yEd.x";
  982. k.type = KeyAttrType.STRING;
  983. data.key = k;
  984. @SuppressWarnings("unchecked")
  985. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  986. while (attributes.hasNext()) {
  987. Attribute a = attributes.next();
  988. try {
  989. switch (a.getName().toString()) {
  990. case "x":
  991. data.value = a.getValue();
  992. break;
  993. case "y":
  994. yPosition.value = a.getValue();
  995. break;
  996. }
  997. } catch (IllegalArgumentException ex) {
  998. throw newParseError(e, "invalid attribute '%s' for '<data>'", a.getName().getLocalPart());
  999. }
  1000. }
  1001. break;
  1002. case "NodeLabel":
  1003. // the label
  1004. data = new Data();
  1005. k = new Key();
  1006. k.def = null;
  1007. k.domain = KeyDomain.ALL;
  1008. k.name = "yEd.label";
  1009. k.type = KeyAttrType.STRING;
  1010. StringBuffer buffer = new StringBuffer();
  1011. e = getNextEvent();
  1012. while (e.isCharacters()) {
  1013. buffer.append(e.asCharacters());
  1014. e = getNextEvent();
  1015. }
  1016. data.key = k;
  1017. data.value = buffer.toString();
  1018. break;
  1019. case "Fill":
  1020. // TODO colour
  1021. break;
  1022. default:
  1023. Debug.out("ignored Yed attribute: " + name);
  1024. data = null;
  1025. break;
  1026. }
  1027. e = getNextEvent();
  1028. while (e.isCharacters() || (e.isEndElement() && e.asEndElement().getName().getPrefix() == "y")) {
  1029. e = getNextEvent();
  1030. }
  1031. pushback(e);
  1032. return data;
  1033. }
  1034. /**
  1035. * <pre>
  1036. * <!ELEMENT graph ((desc)?,((((data)|(node)|(edge)|(hyperedge))*)|(locator)))>
  1037. * <!ATTLIST graph
  1038. * id ID #IMPLIED
  1039. * edgedefault (directed|undirected) #REQUIRED
  1040. * >
  1041. * </pre>
  1042. *
  1043. * @throws IOException
  1044. * @throws XMLStreamException
  1045. */
  1046. private void __graph() throws IOException, XMLStreamException {
  1047. XMLEvent e;
  1048. e = getNextEvent();
  1049. checkValid(e, XMLEvent.START_ELEMENT, "graph");
  1050. @SuppressWarnings("unchecked")
  1051. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1052. String id = null;
  1053. String desc = null;
  1054. boolean directedSet = false;
  1055. while (attributes.hasNext()) {
  1056. Attribute a = attributes.next();
  1057. try {
  1058. GraphAttribute attribute = GraphAttribute.valueOf(toConstantName(a));
  1059. switch (attribute) {
  1060. case ID:
  1061. id = a.getValue();
  1062. break;
  1063. case EDGEDEFAULT:
  1064. if (a.getValue().equals("directed"))
  1065. edgeDefault = true;
  1066. else if (a.getValue().equals("undirected"))
  1067. edgeDefault = false;
  1068. else
  1069. throw newParseError(e, "invalid 'edgefault' value '%s'", a.getValue());
  1070. directedSet = true;
  1071. break;
  1072. }
  1073. } catch (IllegalArgumentException ex) {
  1074. throw newParseError(e, "invalid node attribute '%s'", a.getName().getLocalPart());
  1075. }
  1076. }
  1077. if (!directedSet)
  1078. throw newParseError(e, "graph requires attribute 'edgedefault'");
  1079. String gid = "";
  1080. if (graphId.size() > 0)
  1081. gid = graphId.peek() + ":";
  1082. if (id != null)
  1083. gid += id;
  1084. else
  1085. gid += Integer.toString(graphCounter++);
  1086. graphId.push(gid);
  1087. e = getNextEvent();
  1088. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  1089. pushback(e);
  1090. desc = __desc();
  1091. sendGraphAttributeAdded(sourceId, "desc", desc);
  1092. e = getNextEvent();
  1093. }
  1094. if (isEvent(e, XMLEvent.START_ELEMENT, "locator")) {
  1095. pushback(e);
  1096. __locator();
  1097. e = getNextEvent();
  1098. }
  1099. pushback(e);
  1100. graphId.pop();
  1101. }
  1102. /**
  1103. * <pre>
  1104. * <!ELEMENT node (desc?,(((data|port)*,graph?)|locator))>
  1105. * <!ATTLIST node
  1106. * id ID #REQUIRED
  1107. * >
  1108. * </pre>
  1109. *
  1110. * @throws IOException
  1111. * @throws XMLStreamException
  1112. */
  1113. private void __node() throws IOException, XMLStreamException {
  1114. XMLEvent e;
  1115. e = getNextEvent();
  1116. checkValid(e, XMLEvent.START_ELEMENT, "node");
  1117. @SuppressWarnings("unchecked")
  1118. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1119. String id = null;
  1120. HashSet<Key> sentAttributes = new HashSet<Key>();
  1121. while (attributes.hasNext()) {
  1122. Attribute a = attributes.next();
  1123. try {
  1124. NodeAttribute attribute = NodeAttribute.valueOf(toConstantName(a));
  1125. switch (attribute) {
  1126. case ID:
  1127. id = a.getValue();
  1128. break;
  1129. }
  1130. } catch (IllegalArgumentException ex) {
  1131. throw newParseError(e, "invalid node attribute '%s'", a.getName().getLocalPart());
  1132. }
  1133. }
  1134. if (id == null)
  1135. throw newParseError(e, "node requires an id");
  1136. sendNodeAdded(sourceId, id);
  1137. e = getNextEvent();
  1138. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  1139. String desc;
  1140. pushback(e);
  1141. desc = __desc();
  1142. sendNodeAttributeAdded(sourceId, id, "desc", desc);
  1143. } else if (isEvent(e, XMLEvent.START_ELEMENT, "locator")) {
  1144. pushback(e);
  1145. __locator();
  1146. } else {
  1147. Data data;
  1148. while (isEvent(e, XMLEvent.START_ELEMENT, "data") || isEvent(e, XMLEvent.START_ELEMENT, "port")
  1149. || (e.isStartElement() && e.asStartElement().getName().getPrefix() == "y")
  1150. || isEvent(e, END_ELEMENT, "data")) {
  1151. // Yed parsing
  1152. if (e.getEventType() == XMLEvent.START_ELEMENT && e.asStartElement().getName().getPrefix() == "y") {
  1153. pushback(e);
  1154. data = parseYed();
  1155. if (data != null) {
  1156. if (data.key.name.equals("yEd.x")) {
  1157. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1158. sentAttributes.add(yPosition.key);
  1159. }
  1160. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1161. sentAttributes.add(data.key);
  1162. }
  1163. } else if (isEvent(e, END_ELEMENT, "data")) {
  1164. } else if (isEvent(e, XMLEvent.START_ELEMENT, "data")) {
  1165. XMLEvent yEd = getNextEvent();
  1166. if (yEd.getEventType() == XMLEvent.START_ELEMENT
  1167. && yEd.asStartElement().getName().getPrefix() == "y") {
  1168. pushback(yEd);
  1169. data = parseYed();
  1170. if (data != null) {
  1171. if (data.key.name.equals("yEd.x")) {
  1172. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1173. sentAttributes.add(yPosition.key);
  1174. }
  1175. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1176. sentAttributes.add(data.key);
  1177. }
  1178. } else {
  1179. pushback(yEd);
  1180. pushback(e);
  1181. data = __data();
  1182. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1183. sentAttributes.add(data.key);
  1184. }
  1185. } else {
  1186. pushback(e);
  1187. __port();
  1188. }
  1189. e = getNextEvent();
  1190. }
  1191. }
  1192. //TODO: see if this experimental fix breaks anything
  1193. /*for (Key k : keys.values()) {
  1194. if ((k.domain == KeyDomain.NODE || k.domain == KeyDomain.ALL) && !sentAttributes.contains(k))
  1195. sendNodeAttributeAdded(sourceId, id, k.name, getDefaultValue(k));
  1196. }*/
  1197. if (isEvent(e, XMLEvent.START_ELEMENT, "graph")) {
  1198. Location loc = e.getLocation();
  1199. System.err.printf("[WARNING] %d:%d graph inside node is not implemented", loc.getLineNumber(),
  1200. loc.getColumnNumber());
  1201. pushback(e);
  1202. __graph();
  1203. e = getNextEvent();
  1204. }
  1205. checkValid(e, XMLEvent.END_ELEMENT, "node");
  1206. }
  1207. /**
  1208. * <pre>
  1209. * <!ELEMENT edge ((desc)?,(data)*,(graph)?)>
  1210. * <!ATTLIST edge
  1211. * id ID #IMPLIED
  1212. * source IDREF #REQUIRED
  1213. * sourceport NMTOKEN #IMPLIED
  1214. * target IDREF #REQUIRED
  1215. * targetport NMTOKEN #IMPLIED
  1216. * directed (true|false) #IMPLIED
  1217. * >
  1218. * </pre>
  1219. *
  1220. * @param edgedefault
  1221. * @throws IOException
  1222. * @throws XMLStreamException
  1223. */
  1224. private void __edge(boolean edgedefault) throws IOException, XMLStreamException {
  1225. XMLEvent e;
  1226. e = getNextEvent();
  1227. checkValid(e, XMLEvent.START_ELEMENT, "edge");
  1228. @SuppressWarnings("unchecked")
  1229. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1230. HashSet<Key> sentAttributes = new HashSet<Key>();
  1231. String id = null;
  1232. boolean directed = edgedefault;
  1233. String source = null;
  1234. String target = null;
  1235. while (attributes.hasNext()) {
  1236. Attribute a = attributes.next();
  1237. try {
  1238. EdgeAttribute attribute = EdgeAttribute.valueOf(toConstantName(a));
  1239. switch (attribute) {
  1240. case ID:
  1241. id = a.getValue();
  1242. break;
  1243. case DIRECTED:
  1244. directed = Boolean.parseBoolean(a.getValue());
  1245. break;
  1246. case SOURCE:
  1247. source = a.getValue();
  1248. break;
  1249. case TARGET:
  1250. target = a.getValue();
  1251. break;
  1252. case SOURCEPORT:
  1253. case TARGETPORT:
  1254. throw newParseError(e, "sourceport and targetport not implemented");
  1255. }
  1256. } catch (IllegalArgumentException ex) {
  1257. throw newParseError(e, "invalid graph attribute '%s'", a.getName().getLocalPart());
  1258. }
  1259. }
  1260. if (id == null)
  1261. throw newParseError(e, "edge must have an id");
  1262. if (source == null || target == null)
  1263. throw newParseError(e, "edge must have a source and a target");
  1264. sendEdgeAdded(sourceId, id, source, target, directed);
  1265. e = getNextEvent();
  1266. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  1267. String desc;
  1268. pushback(e);
  1269. desc = __desc();
  1270. sendEdgeAttributeAdded(sourceId, id, "desc", desc);
  1271. } else {
  1272. Data data;
  1273. // parsing yed and graphstream attribute data
  1274. while (isEvent(e, XMLEvent.START_ELEMENT, "data")
  1275. || (e.isStartElement() && e.asStartElement().getName().getPrefix() == "y")
  1276. || isEvent(e, END_ELEMENT, "data")) {
  1277. // Yed parsing
  1278. if (e.getEventType() == XMLEvent.START_ELEMENT && e.asStartElement().getName().getPrefix() == "y") {
  1279. pushback(e);
  1280. data = parseYed();
  1281. if (data != null) {
  1282. if (data.key.name.equals("yEd.x")) {
  1283. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1284. sentAttributes.add(yPosition.key);
  1285. }
  1286. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1287. sentAttributes.add(data.key);
  1288. }
  1289. // </data> is being ignored
  1290. } else if (isEvent(e, END_ELEMENT, "data")) {
  1291. } else {
  1292. XMLEvent yEd = getNextEvent();
  1293. // parsing a <y: > after <data>
  1294. if (yEd.getEventType() == XMLEvent.START_ELEMENT
  1295. && yEd.asStartElement().getName().getPrefix() == "y") {
  1296. pushback(yEd);
  1297. data = parseYed();
  1298. if (data != null) {
  1299. if (data.key.name.equals("yEd.x")) {
  1300. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1301. sentAttributes.add(yPosition.key);
  1302. }
  1303. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1304. sentAttributes.add(data.key);
  1305. }
  1306. // parsing <data>
  1307. } else {
  1308. pushback(yEd);
  1309. pushback(e);
  1310. data = __data();
  1311. sendEdgeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1312. sentAttributes.add(data.key);
  1313. e = getNextEvent();
  1314. }
  1315. }
  1316. }
  1317. }
  1318. for (Key k : keys.values()) {
  1319. if ((k.domain == KeyDomain.EDGE || k.domain == KeyDomain.ALL) && !sentAttributes.contains(k))
  1320. sendEdgeAttributeAdded(sourceId, id, k.name, getDefaultValue(k));
  1321. }
  1322. if (isEvent(e, XMLEvent.START_ELEMENT, "graph")) {
  1323. Location loc = e.getLocation();
  1324. System.err.printf("[WARNING] %d:%d graph inside node is not implemented", loc.getLineNumber(),
  1325. loc.getColumnNumber());
  1326. pushback(e);
  1327. __graph();
  1328. e = getNextEvent();
  1329. }
  1330. checkValid(e, XMLEvent.END_ELEMENT, "edge");
  1331. }
  1332. /**
  1333. * <pre>
  1334. * <!ELEMENT hyperedge ((desc)?,((data)|(endpoint))*,(graph)?)>
  1335. * <!ATTLIST hyperedge
  1336. * id ID #IMPLIED
  1337. * >
  1338. * </pre>
  1339. *
  1340. * @throws IOException
  1341. * @throws XMLStreamException
  1342. */
  1343. private void __hyperedge() throws IOException, XMLStreamException {
  1344. XMLEvent e;
  1345. e = getNextEvent();
  1346. checkValid(e, XMLEvent.START_ELEMENT, "hyperedge");
  1347. Location loc = e.getLocation();
  1348. System.err.printf("[WARNING] %d:%d hyperedge feature is not implemented", loc.getLineNumber(),
  1349. loc.getColumnNumber());
  1350. String id = null;
  1351. @SuppressWarnings("unchecked")
  1352. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1353. while (attributes.hasNext()) {
  1354. Attribute a = attributes.next();
  1355. try {
  1356. HyperEdgeAttribute attribute = HyperEdgeAttribute.valueOf(toConstantName(a));
  1357. switch (attribute) {
  1358. case ID:
  1359. id = a.getValue();
  1360. break;
  1361. }
  1362. } catch (IllegalArgumentException ex) {
  1363. throw newParseError(e, "invalid attribute '%s' for '<endpoint>'", a.getName().getLocalPart());
  1364. }
  1365. }
  1366. if (id == null)
  1367. throw newParseError(e, "'<hyperedge>' element requires a 'node' attribute");
  1368. e = getNextEvent();
  1369. if (isEvent(e, XMLEvent.START_ELEMENT, "desc")) {
  1370. pushback(e);
  1371. __desc();
  1372. } else {
  1373. while (isEvent(e, XMLEvent.START_ELEMENT, "data") || isEvent(e, XMLEvent.START_ELEMENT, "endpoint")) {
  1374. if (isEvent(e, XMLEvent.START_ELEMENT, "data")) {
  1375. pushback(e);
  1376. __data();
  1377. } else {
  1378. pushback(e);
  1379. __endpoint();
  1380. }
  1381. e = getNextEvent();
  1382. }
  1383. }
  1384. if (isEvent(e, XMLEvent.START_ELEMENT, "graph")) {
  1385. loc = e.getLocation();
  1386. System.err.printf("[WARNING] %d:%d graph inside node is not implemented", loc.getLineNumber(),
  1387. loc.getColumnNumber());
  1388. pushback(e);
  1389. __graph();
  1390. e = getNextEvent();
  1391. }
  1392. e = getNextEvent();
  1393. checkValid(e, XMLEvent.END_ELEMENT, "hyperedge");
  1394. }
  1395. }