MyFileSourceGraphML.java 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648
  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. @Override
  231. public void readAll(String fileName) throws IOException {
  232. readAll(new FileReader(fileName));
  233. }
  234. /*
  235. * (non-Javadoc)
  236. *
  237. * @see org.graphstream.stream.file.FileSource#readAll(java.net.URL)
  238. */
  239. @Override
  240. public void readAll(URL url) throws IOException {
  241. readAll(url.openStream());
  242. }
  243. /*
  244. * (non-Javadoc)
  245. *
  246. * @see org.graphstream.stream.file.FileSource#readAll(java.io.InputStream)
  247. */
  248. @Override
  249. public void readAll(InputStream stream) throws IOException {
  250. readAll(new InputStreamReader(stream));
  251. }
  252. /*
  253. * (non-Javadoc)
  254. *
  255. * @see org.graphstream.stream.file.FileSource#readAll(java.io.Reader)
  256. */
  257. @Override
  258. public void readAll(Reader reader) throws IOException {
  259. begin(reader);
  260. while (nextEvents())
  261. ;
  262. end();
  263. }
  264. /*
  265. * (non-Javadoc)
  266. *
  267. * @see org.graphstream.stream.file.FileSource#begin(java.lang.String)
  268. */
  269. @Override
  270. public void begin(String fileName) throws IOException {
  271. begin(new FileReader(fileName));
  272. }
  273. /*
  274. * (non-Javadoc)
  275. *
  276. * @see org.graphstream.stream.file.FileSource#begin(java.net.URL)
  277. */
  278. @Override
  279. public void begin(URL url) throws IOException {
  280. begin(url.openStream());
  281. }
  282. /*
  283. * (non-Javadoc)
  284. *
  285. * @see org.graphstream.stream.file.FileSource#begin(java.io.InputStream)
  286. */
  287. @Override
  288. public void begin(InputStream stream) throws IOException {
  289. begin(new InputStreamReader(stream));
  290. }
  291. /*
  292. * (non-Javadoc)
  293. *
  294. * @see org.graphstream.stream.file.FileSource#begin(java.io.Reader)
  295. */
  296. @Override
  297. public void begin(Reader reader) throws IOException {
  298. openStream(reader);
  299. }
  300. /*
  301. * (non-Javadoc)
  302. *
  303. * @see org.graphstream.stream.file.FileSource#nextEvents()
  304. */
  305. @Override
  306. public boolean nextEvents() throws IOException {
  307. try {
  308. __graphml();
  309. } catch (XMLStreamException ex) {
  310. throw new IOException(ex);
  311. }
  312. return false;
  313. }
  314. /*
  315. * (non-Javadoc)
  316. *
  317. * @see org.graphstream.stream.file.FileSource#nextStep()
  318. */
  319. @Override
  320. public boolean nextStep() throws IOException {
  321. return nextEvents();
  322. }
  323. /*
  324. * (non-Javadoc)
  325. *
  326. * @see org.graphstream.stream.file.FileSource#end()
  327. */
  328. @Override
  329. public void end() throws IOException {
  330. closeStream();
  331. }
  332. protected XMLEvent getNextEvent() throws IOException, XMLStreamException {
  333. skipWhiteSpaces();
  334. XMLEvent temp;
  335. if (events.size() > 0)
  336. temp = events.pop();
  337. else {
  338. temp = reader.nextEvent();
  339. }
  340. if (temp.getEventType() == XMLStreamConstants.COMMENT) {
  341. temp = getNextEvent();
  342. }
  343. return temp;
  344. }
  345. protected void pushback(XMLEvent e) {
  346. events.push(e);
  347. }
  348. private XMLStreamException newParseError(XMLEvent e, String msg, Object... args) {
  349. return new XMLStreamException(String.format(msg, args), e.getLocation());
  350. }
  351. private boolean isEvent(XMLEvent e, int type, String name) {
  352. boolean valid = e.getEventType() == type;
  353. if (valid) {
  354. switch (type) {
  355. case START_ELEMENT:
  356. valid = e.asStartElement().getName().getLocalPart().equals(name);
  357. break;
  358. case END_ELEMENT:
  359. valid = e.asEndElement().getName().getLocalPart().equals(name);
  360. break;
  361. case ATTRIBUTE:
  362. valid = ((Attribute) e).getName().getLocalPart().equals(name);
  363. break;
  364. case CHARACTERS:
  365. case NAMESPACE:
  366. case PROCESSING_INSTRUCTION:
  367. case START_DOCUMENT:
  368. case END_DOCUMENT:
  369. case DTD:
  370. }
  371. }
  372. return valid;
  373. }
  374. private void checkValid(XMLEvent e, int type, String name) throws XMLStreamException {
  375. boolean valid = isEvent(e, type, name);
  376. if (!valid)
  377. throw newParseError(e, "expecting %s, got %s", gotWhat(type, name), gotWhat(e));
  378. }
  379. private String gotWhat(XMLEvent e) {
  380. String v = null;
  381. switch (e.getEventType()) {
  382. case START_ELEMENT:
  383. v = e.asStartElement().getName().getLocalPart();
  384. break;
  385. case END_ELEMENT:
  386. v = e.asEndElement().getName().getLocalPart();
  387. break;
  388. case ATTRIBUTE:
  389. v = ((Attribute) e).getName().getLocalPart();
  390. break;
  391. }
  392. return gotWhat(e.getEventType(), v);
  393. }
  394. public String gotWhat(int type, String v) {
  395. switch (type) {
  396. case START_ELEMENT:
  397. return String.format("'<%s>'", v);
  398. case END_ELEMENT:
  399. return String.format("'</%s>'", v);
  400. case ATTRIBUTE:
  401. return String.format("attribute '%s'", v);
  402. case NAMESPACE:
  403. return "namespace";
  404. case PROCESSING_INSTRUCTION:
  405. return "processing instruction";
  406. case COMMENT:
  407. return "comment";
  408. case START_DOCUMENT:
  409. return "document start";
  410. case END_DOCUMENT:
  411. return "document end";
  412. case DTD:
  413. return "dtd";
  414. case CHARACTERS:
  415. return "characters";
  416. default:
  417. return "UNKNOWN";
  418. }
  419. }
  420. private Object getValue(Data data) {
  421. switch (data.key.type) {
  422. case BOOLEAN:
  423. if (data.value == null || data.value.equals(""))
  424. return false;
  425. return Boolean.parseBoolean(data.value);
  426. case INT:
  427. if (data.value == null || data.value.equals(""))
  428. return new Integer(0);
  429. return Integer.parseInt(data.value);
  430. case LONG:
  431. if (data.value == null || data.value.equals(""))
  432. return new Long(0);
  433. return Long.parseLong(data.value);
  434. case FLOAT:
  435. if (data.value == null || data.value.equals(""))
  436. return new Float(0);
  437. return Float.parseFloat(data.value);
  438. case DOUBLE:
  439. if (data.value == null || data.value.equals(""))
  440. return new Double(0);
  441. return Double.parseDouble(data.value);
  442. case STRING:
  443. return data.value;
  444. }
  445. return data.value;
  446. }
  447. private Object getDefaultValue(Key key) {
  448. switch (key.type) {
  449. case BOOLEAN:
  450. return Boolean.TRUE;
  451. case INT:
  452. if (key.def != null)
  453. return Integer.valueOf(key.def);
  454. return Integer.valueOf(0);
  455. case LONG:
  456. if (key.def != null)
  457. return Long.valueOf(key.def);
  458. return Long.valueOf(0);
  459. case FLOAT:
  460. if (key.def != null)
  461. return Float.valueOf(key.def);
  462. return Float.valueOf(0.0f);
  463. case DOUBLE:
  464. if (key.def != null)
  465. return Double.valueOf(key.def);
  466. return Double.valueOf(0.0);
  467. case STRING:
  468. if (key.def != null)
  469. return key.def;
  470. return "";
  471. }
  472. return key.def != null ? key.def : Boolean.TRUE;
  473. }
  474. private void skipWhiteSpaces() throws IOException, XMLStreamException {
  475. XMLEvent e;
  476. do {
  477. if (events.size() > 0)
  478. e = events.pop();
  479. else
  480. e = reader.nextEvent();
  481. } while (isEvent(e, XMLStreamConstants.CHARACTERS, null) && e.asCharacters().getData().matches("^\\s*$"));
  482. pushback(e);
  483. }
  484. protected void openStream(Reader stream) throws IOException {
  485. if (reader != null)
  486. closeStream();
  487. try {
  488. XMLEvent e;
  489. reader = XMLInputFactory.newInstance().createXMLEventReader(stream);
  490. e = getNextEvent();
  491. checkValid(e, XMLStreamConstants.START_DOCUMENT, null);
  492. } catch (XMLStreamException e) {
  493. throw new IOException(e);
  494. } catch (FactoryConfigurationError e) {
  495. throw new IOException(e);
  496. }
  497. }
  498. protected void closeStream() throws IOException {
  499. try {
  500. reader.close();
  501. } catch (XMLStreamException e) {
  502. throw new IOException(e);
  503. } finally {
  504. reader = null;
  505. }
  506. }
  507. protected String toConstantName(Attribute a) {
  508. return toConstantName(a.getName().getLocalPart());
  509. }
  510. protected String toConstantName(String value) {
  511. return value.toUpperCase().replaceAll("\\W", "_");
  512. }
  513. /**
  514. * parses a Stream of xml Events to a graphstream graph it has limited
  515. * support for yEd attributes
  516. *
  517. * @throws IOException
  518. * @throws XMLStreamException
  519. */
  520. private void __graphml() throws IOException, XMLStreamException {
  521. XMLEvent e;
  522. e = getNextEvent();
  523. // reading the file
  524. while (true) {
  525. switch (currentReaderState) {
  526. case START:
  527. checkValid(e, XMLStreamConstants.START_ELEMENT, "graphml");
  528. currentReaderState = ReaderState.DESC;
  529. e = getNextEvent();
  530. break;
  531. case DESC:
  532. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  533. pushback(e);
  534. __desc();
  535. e = getNextEvent();
  536. } else {
  537. currentReaderState = ReaderState.KEYS;
  538. }
  539. break;
  540. case KEYS:
  541. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "key")) {
  542. pushback(e);
  543. __key();
  544. e = getNextEvent();
  545. } else {
  546. currentReaderState = ReaderState.NEW_GRAPH;
  547. }
  548. break;
  549. case NEW_GRAPH:
  550. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "graph")) {
  551. newSubGraph();
  552. pushback(e);
  553. __graph();
  554. e = getNextEvent();
  555. }
  556. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "node") || isEvent(e, XMLStreamConstants.START_ELEMENT, "edge")) {
  557. currentReaderState = ReaderState.NODES_EDGES;
  558. } else if (isEvent(e, XMLStreamConstants.END_ELEMENT, "graph")) {
  559. currentReaderState = ReaderState.GRAPH_END;
  560. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")) {
  561. pushback(e);
  562. Data data = __data();
  563. sendGraphAttributeAdded(sourceId, data.key.name, data.value);
  564. e = getNextEvent();
  565. } else {
  566. throw newParseError(e, "expecting %s, got %s", "<graph>, </graph>, <node>, <edge> or <data>",
  567. gotWhat(e));
  568. }
  569. break;
  570. case NODES_EDGES:
  571. pushback(e);
  572. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "node")) {
  573. __node();
  574. e = getNextEvent();
  575. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "edge")) {
  576. __edge(edgeDefault);
  577. e = getNextEvent();
  578. } else if (isEvent(e, XMLStreamConstants.END_ELEMENT, "graph")) {
  579. currentReaderState = ReaderState.GRAPH_END;
  580. e = getNextEvent();
  581. } else if (isEvent(e, XMLStreamConstants.END_ELEMENT, "graphml")) {
  582. currentReaderState = ReaderState.END;
  583. e = getNextEvent();
  584. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")) {
  585. datas.add(__data());
  586. e = getNextEvent();
  587. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "hyperedge")) {
  588. __hyperedge();
  589. e = getNextEvent();
  590. } else {
  591. throw newParseError(e, "expecting %s, got %s", "</graph>, <node> or <edge>", gotWhat(e));
  592. }
  593. break;
  594. case GRAPH_END:
  595. if (isEvent(e, END_ELEMENT, "graph")) {
  596. e = getNextEvent();
  597. subGraphFinished();
  598. }
  599. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "graph")) {
  600. currentReaderState = ReaderState.NEW_GRAPH;
  601. } else if (isEvent(e, XMLStreamConstants.END_ELEMENT, "graphml")) {
  602. currentReaderState = ReaderState.END;
  603. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "key")) {
  604. currentReaderState = ReaderState.KEYS;
  605. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "node") || isEvent(e, XMLStreamConstants.START_ELEMENT, "edge")) {
  606. currentReaderState = ReaderState.NODES_EDGES;
  607. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")) {
  608. // ignore <data>
  609. pushback(e);
  610. __data();
  611. e = getNextEvent();
  612. } else {
  613. throw newParseError(e, "expecting %s, got %s", "<data>, <graph>, </graphml> or <key>", gotWhat(e));
  614. }
  615. break;
  616. case END:
  617. currentReaderState = ReaderState.START;
  618. init();
  619. return;
  620. }
  621. }
  622. }
  623. private String __characters() throws IOException, XMLStreamException {
  624. XMLEvent e;
  625. StringBuilder buffer = new StringBuilder();
  626. e = getNextEvent();
  627. while (e.getEventType() == XMLStreamConstants.CHARACTERS) {
  628. buffer.append(e.asCharacters());
  629. e = getNextEvent();
  630. }
  631. pushback(e);
  632. return buffer.toString();
  633. }
  634. /**
  635. * <pre>
  636. * <!ELEMENT desc (#PCDATA)>
  637. * </pre>
  638. *
  639. * @return
  640. * @throws IOException
  641. * @throws XMLStreamException
  642. */
  643. private String __desc() throws IOException, XMLStreamException {
  644. XMLEvent e;
  645. String desc;
  646. e = getNextEvent();
  647. checkValid(e, XMLStreamConstants.START_ELEMENT, "desc");
  648. desc = __characters();
  649. e = getNextEvent();
  650. checkValid(e, XMLStreamConstants.END_ELEMENT, "desc");
  651. return desc;
  652. }
  653. /**
  654. * <pre>
  655. * <!ELEMENT locator EMPTY>
  656. * <!ATTLIST locator
  657. * xmlns:xlink CDATA #FIXED "http://www.w3.org/TR/2000/PR-xlink-20001220/"
  658. * xlink:href CDATA #REQUIRED
  659. * xlink:type (simple) #FIXED "simple"
  660. * >
  661. * </pre>
  662. *
  663. * @return
  664. * @throws IOException
  665. * @throws XMLStreamException
  666. */
  667. private Locator __locator() throws IOException, XMLStreamException {
  668. XMLEvent e;
  669. e = getNextEvent();
  670. checkValid(e, XMLStreamConstants.START_ELEMENT, "locator");
  671. @SuppressWarnings("unchecked")
  672. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  673. Locator loc = new Locator();
  674. while (attributes.hasNext()) {
  675. Attribute a = attributes.next();
  676. try {
  677. LocatorAttribute attribute = LocatorAttribute.valueOf(toConstantName(a));
  678. switch (attribute) {
  679. case XMLNS_XLINK:
  680. loc.xlink = a.getValue();
  681. break;
  682. case XLINK_HREF:
  683. loc.href = a.getValue();
  684. break;
  685. case XLINK_TYPE:
  686. loc.type = a.getValue();
  687. break;
  688. }
  689. } catch (IllegalArgumentException ex) {
  690. throw newParseError(e, "invalid locator attribute '%s'", a.getName().getLocalPart());
  691. }
  692. }
  693. e = getNextEvent();
  694. checkValid(e, XMLStreamConstants.END_ELEMENT, "locator");
  695. if (loc.href == null)
  696. throw newParseError(e, "locator requires an href");
  697. return loc;
  698. }
  699. /**
  700. * <pre>
  701. * <!ELEMENT key (#PCDATA)>
  702. * <!ATTLIST key
  703. * id ID #REQUIRED
  704. * for (graphml|graph|node|edge|hyperedge|port|endpoint|all) "all"
  705. * >
  706. * </pre>
  707. *
  708. * @throws IOException
  709. * @throws XMLStreamException
  710. */
  711. private void __key() throws IOException, XMLStreamException {
  712. XMLEvent e;
  713. e = getNextEvent();
  714. checkValid(e, XMLStreamConstants.START_ELEMENT, "key");
  715. @SuppressWarnings("unchecked")
  716. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  717. String id = null;
  718. KeyDomain domain = KeyDomain.ALL;
  719. KeyAttrType type = KeyAttrType.STRING;
  720. String name = null;
  721. String def = null;
  722. while (attributes.hasNext()) {
  723. Attribute a = attributes.next();
  724. try {
  725. KeyAttribute attribute = KeyAttribute.valueOf(toConstantName(a));
  726. switch (attribute) {
  727. case ID:
  728. id = a.getValue();
  729. break;
  730. case FOR:
  731. try {
  732. domain = KeyDomain.valueOf(toConstantName(a.getValue()));
  733. } catch (IllegalArgumentException ex) {
  734. throw newParseError(e, "invalid key domain '%s'", a.getValue());
  735. }
  736. break;
  737. case ATTR_TYPE:
  738. try {
  739. type = KeyAttrType.valueOf(toConstantName(a.getValue()));
  740. } catch (IllegalArgumentException ex) {
  741. throw newParseError(e, "invalid key type '%s'", a.getValue());
  742. }
  743. break;
  744. case ATTR_NAME:
  745. name = a.getValue();
  746. break;
  747. case YFILES_TYPE:
  748. break;
  749. }
  750. } catch (IllegalArgumentException ex) {
  751. throw newParseError(e, "invalid key attribute '%s'", a.getName().getLocalPart());
  752. }
  753. }
  754. e = getNextEvent();
  755. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "default")) {
  756. def = __characters();
  757. e = getNextEvent();
  758. checkValid(e, XMLStreamConstants.END_ELEMENT, "default");
  759. e = getNextEvent();
  760. }
  761. checkValid(e, XMLStreamConstants.END_ELEMENT, "key");
  762. if (id == null)
  763. throw newParseError(e, "key requires an id");
  764. if (name == null)
  765. name = id;
  766. Debug.out("add key \"" + id + "\"", 1);
  767. Key k = new Key();
  768. k.name = name;
  769. k.domain = domain;
  770. k.type = type;
  771. k.def = def;
  772. keys.put(id, k);
  773. }
  774. /**
  775. * <pre>
  776. * <!ELEMENT port ((desc)?,((data)|(port))*)>
  777. * <!ATTLIST port
  778. * name NMTOKEN #REQUIRED
  779. * >
  780. * </pre>
  781. *
  782. * @return
  783. * @throws IOException
  784. * @throws XMLStreamException
  785. */
  786. private Port __port() throws IOException, XMLStreamException {
  787. XMLEvent e;
  788. e = getNextEvent();
  789. checkValid(e, XMLStreamConstants.START_ELEMENT, "port");
  790. Port port = new Port();
  791. @SuppressWarnings("unchecked")
  792. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  793. while (attributes.hasNext()) {
  794. Attribute a = attributes.next();
  795. try {
  796. PortAttribute attribute = PortAttribute.valueOf(toConstantName(a));
  797. switch (attribute) {
  798. case NAME:
  799. port.name = a.getValue();
  800. break;
  801. }
  802. } catch (IllegalArgumentException ex) {
  803. throw newParseError(e, "invalid attribute '%s' for '<port>'", a.getName().getLocalPart());
  804. }
  805. }
  806. if (port.name == null)
  807. throw newParseError(e, "'<port>' element requires a 'name' attribute");
  808. e = getNextEvent();
  809. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  810. pushback(e);
  811. port.desc = __desc();
  812. } else {
  813. while (isEvent(e, XMLStreamConstants.START_ELEMENT, "data") || isEvent(e, XMLStreamConstants.START_ELEMENT, "port")) {
  814. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")) {
  815. Data data;
  816. pushback(e);
  817. data = __data();
  818. port.datas.add(data);
  819. } else {
  820. Port portChild;
  821. pushback(e);
  822. portChild = __port();
  823. port.ports.add(portChild);
  824. }
  825. e = getNextEvent();
  826. }
  827. }
  828. e = getNextEvent();
  829. checkValid(e, XMLStreamConstants.END_ELEMENT, "port");
  830. return port;
  831. }
  832. /**
  833. * <pre>
  834. * <!ELEMENT endpoint ((desc)?)>
  835. * <!ATTLIST endpoint
  836. * id ID #IMPLIED
  837. * node IDREF #REQUIRED
  838. * port NMTOKEN #IMPLIED
  839. * type (in|out|undir) "undir"
  840. * >
  841. * </pre>
  842. *
  843. * @return
  844. * @throws IOException
  845. * @throws XMLStreamException
  846. */
  847. private EndPoint __endpoint() throws IOException, XMLStreamException {
  848. XMLEvent e;
  849. e = getNextEvent();
  850. checkValid(e, XMLStreamConstants.START_ELEMENT, "endpoint");
  851. @SuppressWarnings("unchecked")
  852. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  853. EndPoint ep = new EndPoint();
  854. while (attributes.hasNext()) {
  855. Attribute a = attributes.next();
  856. try {
  857. EndPointAttribute attribute = EndPointAttribute.valueOf(toConstantName(a));
  858. switch (attribute) {
  859. case NODE:
  860. ep.node = a.getValue();
  861. break;
  862. case ID:
  863. ep.id = a.getValue();
  864. break;
  865. case PORT:
  866. ep.port = a.getValue();
  867. break;
  868. case TYPE:
  869. try {
  870. ep.type = EndPointType.valueOf(toConstantName(a.getValue()));
  871. } catch (IllegalArgumentException ex) {
  872. throw newParseError(e, "invalid end point type '%s'", a.getValue());
  873. }
  874. break;
  875. }
  876. } catch (IllegalArgumentException ex) {
  877. throw newParseError(e, "invalid attribute '%s' for '<endpoint>'", a.getName().getLocalPart());
  878. }
  879. }
  880. if (ep.node == null)
  881. throw newParseError(e, "'<endpoint>' element requires a 'node' attribute");
  882. e = getNextEvent();
  883. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  884. pushback(e);
  885. ep.desc = __desc();
  886. }
  887. e = getNextEvent();
  888. checkValid(e, XMLStreamConstants.END_ELEMENT, "endpoint");
  889. return ep;
  890. }
  891. /**
  892. * <pre>
  893. * <!ELEMENT data (#PCDATA)>
  894. * <!ATTLIST data
  895. * key IDREF #REQUIRED
  896. * id ID #IMPLIED
  897. * >
  898. * </pre>
  899. *
  900. * @return
  901. * @throws IOException
  902. * @throws XMLStreamException
  903. */
  904. private Data __data() throws IOException, XMLStreamException {
  905. XMLEvent e;
  906. StringBuilder buffer = new StringBuilder();
  907. e = getNextEvent();
  908. checkValid(e, XMLStreamConstants.START_ELEMENT, "data");
  909. @SuppressWarnings("unchecked")
  910. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  911. String key = null, id = null;
  912. while (attributes.hasNext()) {
  913. Attribute a = attributes.next();
  914. try {
  915. DataAttribute attribute = DataAttribute.valueOf(toConstantName(a));
  916. switch (attribute) {
  917. case KEY:
  918. key = a.getValue();
  919. break;
  920. case ID:
  921. id = a.getValue();
  922. break;
  923. }
  924. } catch (IllegalArgumentException ex) {
  925. throw newParseError(e, "invalid attribute '%s' for '<data>'", a.getName().getLocalPart());
  926. }
  927. }
  928. if (key == null)
  929. throw newParseError(e, "'<data>' element must have a 'key' attribute");
  930. e = getNextEvent();
  931. while (e.getEventType() == XMLStreamConstants.CHARACTERS) {
  932. buffer.append(e.asCharacters());
  933. e = getNextEvent();
  934. }
  935. if (e.isStartElement() && e.asStartElement().getName().getPrefix() == "y") {
  936. pushback(e);
  937. parseYed();
  938. e = getNextEvent();
  939. }
  940. checkValid(e, XMLStreamConstants.END_ELEMENT, "data");
  941. if (keys.containsKey(key))
  942. newParseError(e, "unknown key '%s'", key);
  943. Data d = new Data();
  944. d.key = keys.get(key);
  945. d.id = id;
  946. d.value = buffer.toString();
  947. return d;
  948. }
  949. /**
  950. * Parses a yEdattribute. returns null if the Attribute is unknown.
  951. *
  952. * The known Attributes are:
  953. * <li>position of nodes</li>
  954. * <li>The label of Nodes</li>
  955. * <li>color of nodes</li>
  956. *
  957. * @return the parsed yEd Attribute as a Data object
  958. * @throws IOException
  959. * @throws XMLStreamException
  960. */
  961. private Data parseYed() throws IOException, XMLStreamException {
  962. XMLEvent e = getNextEvent();
  963. String name = null;
  964. if (e.getEventType() == START_ELEMENT) {
  965. name = e.asStartElement().getName().getLocalPart();
  966. } else if (e.getEventType() == END_ELEMENT) {
  967. name = e.asEndElement().getName().getLocalPart();
  968. } else {
  969. newParseError(e, "expected XMLEvent.START_ELEMENT or XMLEvent.END_ELEMENT, got neither", "");
  970. }
  971. // converting yed attributes
  972. Data data = null;
  973. Key k = null;
  974. switch (name) {
  975. case "Geometry":
  976. // the coordinates
  977. yPosition = new Data();
  978. k = new Key();
  979. k.def = null;
  980. k.domain = KeyDomain.ALL;
  981. k.name = "yEd.y";
  982. k.type = KeyAttrType.DOUBLE;
  983. yPosition.key = k;
  984. data = new Data();
  985. k = new Key();
  986. k.def = null;
  987. k.domain = KeyDomain.ALL;
  988. k.name = "yEd.x";
  989. k.type = KeyAttrType.STRING;
  990. data.key = k;
  991. @SuppressWarnings("unchecked")
  992. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  993. while (attributes.hasNext()) {
  994. Attribute a = attributes.next();
  995. try {
  996. switch (a.getName().toString()) {
  997. case "x":
  998. data.value = a.getValue();
  999. break;
  1000. case "y":
  1001. yPosition.value = a.getValue();
  1002. break;
  1003. }
  1004. } catch (IllegalArgumentException ex) {
  1005. throw newParseError(e, "invalid attribute '%s' for '<data>'", a.getName().getLocalPart());
  1006. }
  1007. }
  1008. break;
  1009. case "NodeLabel":
  1010. // the label
  1011. data = new Data();
  1012. k = new Key();
  1013. k.def = null;
  1014. k.domain = KeyDomain.ALL;
  1015. k.name = "yEd.label";
  1016. k.type = KeyAttrType.STRING;
  1017. StringBuffer buffer = new StringBuffer();
  1018. e = getNextEvent();
  1019. while (e.isCharacters()) {
  1020. buffer.append(e.asCharacters());
  1021. e = getNextEvent();
  1022. }
  1023. data.key = k;
  1024. data.value = buffer.toString();
  1025. break;
  1026. default:
  1027. Debug.out("ignored Yed attribute: " + name, 1);
  1028. data = null;
  1029. break;
  1030. }
  1031. e = getNextEvent();
  1032. while (e.isCharacters() || (e.isEndElement() && e.asEndElement().getName().getPrefix() == "y")) {
  1033. e = getNextEvent();
  1034. }
  1035. pushback(e);
  1036. return data;
  1037. }
  1038. /**
  1039. * <pre>
  1040. * <!ELEMENT graph ((desc)?,((((data)|(node)|(edge)|(hyperedge))*)|(locator)))>
  1041. * <!ATTLIST graph
  1042. * id ID #IMPLIED
  1043. * edgedefault (directed|undirected) #REQUIRED
  1044. * >
  1045. * </pre>
  1046. *
  1047. * @throws IOException
  1048. * @throws XMLStreamException
  1049. */
  1050. private void __graph() throws IOException, XMLStreamException {
  1051. XMLEvent e;
  1052. e = getNextEvent();
  1053. checkValid(e, XMLStreamConstants.START_ELEMENT, "graph");
  1054. @SuppressWarnings("unchecked")
  1055. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1056. String id = null;
  1057. String desc = null;
  1058. boolean directedSet = false;
  1059. while (attributes.hasNext()) {
  1060. Attribute a = attributes.next();
  1061. try {
  1062. GraphAttribute attribute = GraphAttribute.valueOf(toConstantName(a));
  1063. switch (attribute) {
  1064. case ID:
  1065. id = a.getValue();
  1066. break;
  1067. case EDGEDEFAULT:
  1068. if (a.getValue().equals("directed"))
  1069. edgeDefault = true;
  1070. else if (a.getValue().equals("undirected"))
  1071. edgeDefault = false;
  1072. else
  1073. throw newParseError(e, "invalid 'edgefault' value '%s'", a.getValue());
  1074. directedSet = true;
  1075. break;
  1076. }
  1077. } catch (IllegalArgumentException ex) {
  1078. throw newParseError(e, "invalid node attribute '%s'", a.getName().getLocalPart());
  1079. }
  1080. }
  1081. if (!directedSet)
  1082. throw newParseError(e, "graph requires attribute 'edgedefault'");
  1083. String gid = "";
  1084. if (graphId.size() > 0)
  1085. gid = graphId.peek() + ":";
  1086. if (id != null)
  1087. gid += id;
  1088. else
  1089. gid += Integer.toString(graphCounter++);
  1090. graphId.push(gid);
  1091. e = getNextEvent();
  1092. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  1093. pushback(e);
  1094. desc = __desc();
  1095. sendGraphAttributeAdded(sourceId, "desc", desc);
  1096. e = getNextEvent();
  1097. }
  1098. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "locator")) {
  1099. pushback(e);
  1100. __locator();
  1101. e = getNextEvent();
  1102. }
  1103. pushback(e);
  1104. graphId.pop();
  1105. }
  1106. /**
  1107. * <pre>
  1108. * <!ELEMENT node (desc?,(((data|port)*,graph?)|locator))>
  1109. * <!ATTLIST node
  1110. * id ID #REQUIRED
  1111. * >
  1112. * </pre>
  1113. *
  1114. * @throws IOException
  1115. * @throws XMLStreamException
  1116. */
  1117. private void __node() throws IOException, XMLStreamException {
  1118. XMLEvent e;
  1119. e = getNextEvent();
  1120. checkValid(e, XMLStreamConstants.START_ELEMENT, "node");
  1121. @SuppressWarnings("unchecked")
  1122. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1123. String id = null;
  1124. HashSet<Key> sentAttributes = new HashSet<Key>();
  1125. while (attributes.hasNext()) {
  1126. Attribute a = attributes.next();
  1127. try {
  1128. NodeAttribute attribute = NodeAttribute.valueOf(toConstantName(a));
  1129. switch (attribute) {
  1130. case ID:
  1131. id = a.getValue();
  1132. break;
  1133. }
  1134. } catch (IllegalArgumentException ex) {
  1135. throw newParseError(e, "invalid node attribute '%s'", a.getName().getLocalPart());
  1136. }
  1137. }
  1138. if (id == null)
  1139. throw newParseError(e, "node requires an id");
  1140. sendNodeAdded(sourceId, id);
  1141. e = getNextEvent();
  1142. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  1143. String desc;
  1144. pushback(e);
  1145. desc = __desc();
  1146. sendNodeAttributeAdded(sourceId, id, "desc", desc);
  1147. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "locator")) {
  1148. pushback(e);
  1149. __locator();
  1150. } else {
  1151. Data data;
  1152. while (isEvent(e, XMLStreamConstants.START_ELEMENT, "data") || isEvent(e, XMLStreamConstants.START_ELEMENT, "port")
  1153. || (e.isStartElement() && e.asStartElement().getName().getPrefix() == "y")
  1154. || isEvent(e, END_ELEMENT, "data")) {
  1155. // Yed parsing
  1156. if (e.getEventType() == XMLStreamConstants.START_ELEMENT && e.asStartElement().getName().getPrefix() == "y") {
  1157. pushback(e);
  1158. data = parseYed();
  1159. if (data != null) {
  1160. if (data.key.name.equals("yEd.x")) {
  1161. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1162. sentAttributes.add(yPosition.key);
  1163. }
  1164. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1165. sentAttributes.add(data.key);
  1166. }
  1167. } else if (isEvent(e, END_ELEMENT, "data")) {
  1168. } else if (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")) {
  1169. XMLEvent yEd = getNextEvent();
  1170. if (yEd.getEventType() == XMLStreamConstants.START_ELEMENT
  1171. && yEd.asStartElement().getName().getPrefix() == "y") {
  1172. pushback(yEd);
  1173. data = parseYed();
  1174. if (data != null) {
  1175. if (data.key.name.equals("yEd.x")) {
  1176. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1177. sentAttributes.add(yPosition.key);
  1178. }
  1179. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1180. sentAttributes.add(data.key);
  1181. }
  1182. } else {
  1183. pushback(yEd);
  1184. pushback(e);
  1185. data = __data();
  1186. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1187. sentAttributes.add(data.key);
  1188. }
  1189. } else {
  1190. pushback(e);
  1191. __port();
  1192. }
  1193. e = getNextEvent();
  1194. }
  1195. }
  1196. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "graph")) {
  1197. Location loc = e.getLocation();
  1198. Debug.out(String.format("[WARNING] %d:%d graph inside node is not implemented", loc.getLineNumber(),
  1199. loc.getColumnNumber()), 2);
  1200. pushback(e);
  1201. __graph();
  1202. e = getNextEvent();
  1203. }
  1204. checkValid(e, XMLStreamConstants.END_ELEMENT, "node");
  1205. }
  1206. /**
  1207. * <pre>
  1208. * <!ELEMENT edge ((desc)?,(data)*,(graph)?)>
  1209. * <!ATTLIST edge
  1210. * id ID #IMPLIED
  1211. * source IDREF #REQUIRED
  1212. * sourceport NMTOKEN #IMPLIED
  1213. * target IDREF #REQUIRED
  1214. * targetport NMTOKEN #IMPLIED
  1215. * directed (true|false) #IMPLIED
  1216. * >
  1217. * </pre>
  1218. *
  1219. * @param edgedefault
  1220. * @throws IOException
  1221. * @throws XMLStreamException
  1222. */
  1223. private void __edge(boolean edgedefault) throws IOException, XMLStreamException {
  1224. XMLEvent e;
  1225. e = getNextEvent();
  1226. checkValid(e, XMLStreamConstants.START_ELEMENT, "edge");
  1227. @SuppressWarnings("unchecked")
  1228. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1229. HashSet<Key> sentAttributes = new HashSet<Key>();
  1230. String id = null;
  1231. boolean directed = edgedefault;
  1232. String source = null;
  1233. String target = null;
  1234. while (attributes.hasNext()) {
  1235. Attribute a = attributes.next();
  1236. try {
  1237. EdgeAttribute attribute = EdgeAttribute.valueOf(toConstantName(a));
  1238. switch (attribute) {
  1239. case ID:
  1240. id = a.getValue();
  1241. break;
  1242. case DIRECTED:
  1243. directed = Boolean.parseBoolean(a.getValue());
  1244. break;
  1245. case SOURCE:
  1246. source = a.getValue();
  1247. break;
  1248. case TARGET:
  1249. target = a.getValue();
  1250. break;
  1251. case SOURCEPORT:
  1252. case TARGETPORT:
  1253. throw newParseError(e, "sourceport and targetport not implemented");
  1254. }
  1255. } catch (IllegalArgumentException ex) {
  1256. throw newParseError(e, "invalid graph attribute '%s'", a.getName().getLocalPart());
  1257. }
  1258. }
  1259. if (id == null)
  1260. throw newParseError(e, "edge must have an id");
  1261. if (source == null || target == null)
  1262. throw newParseError(e, "edge must have a source and a target");
  1263. sendEdgeAdded(sourceId, id, source, target, directed);
  1264. e = getNextEvent();
  1265. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  1266. String desc;
  1267. pushback(e);
  1268. desc = __desc();
  1269. sendEdgeAttributeAdded(sourceId, id, "desc", desc);
  1270. } else {
  1271. Data data;
  1272. // parsing yed and graphstream attribute data
  1273. while (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")
  1274. || (e.isStartElement() && e.asStartElement().getName().getPrefix() == "y")
  1275. || isEvent(e, END_ELEMENT, "data")) {
  1276. // Yed parsing
  1277. if (e.getEventType() == XMLStreamConstants.START_ELEMENT && e.asStartElement().getName().getPrefix() == "y") {
  1278. pushback(e);
  1279. data = parseYed();
  1280. if (data != null) {
  1281. if (data.key.name.equals("yEd.x")) {
  1282. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1283. sentAttributes.add(yPosition.key);
  1284. }
  1285. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1286. sentAttributes.add(data.key);
  1287. }
  1288. // </data> is being ignored
  1289. } else if (isEvent(e, END_ELEMENT, "data")) {
  1290. } else {
  1291. XMLEvent yEd = getNextEvent();
  1292. // parsing a <y: > after <data>
  1293. if (yEd.getEventType() == XMLStreamConstants.START_ELEMENT
  1294. && yEd.asStartElement().getName().getPrefix() == "y") {
  1295. pushback(yEd);
  1296. data = parseYed();
  1297. if (data != null) {
  1298. if (data.key.name.equals("yEd.x")) {
  1299. sendNodeAttributeAdded(sourceId, id, yPosition.key.name, getValue(yPosition));
  1300. sentAttributes.add(yPosition.key);
  1301. }
  1302. sendNodeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1303. sentAttributes.add(data.key);
  1304. }
  1305. // parsing <data>
  1306. } else {
  1307. pushback(yEd);
  1308. pushback(e);
  1309. data = __data();
  1310. sendEdgeAttributeAdded(sourceId, id, data.key.name, getValue(data));
  1311. sentAttributes.add(data.key);
  1312. e = getNextEvent();
  1313. }
  1314. }
  1315. }
  1316. }
  1317. for (Key k : keys.values()) {
  1318. if ((k.domain == KeyDomain.EDGE || k.domain == KeyDomain.ALL) && !sentAttributes.contains(k))
  1319. sendEdgeAttributeAdded(sourceId, id, k.name, getDefaultValue(k));
  1320. }
  1321. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "graph")) {
  1322. Location loc = e.getLocation();
  1323. System.err.printf("[WARNING] %d:%d graph inside node is not implemented", loc.getLineNumber(),
  1324. loc.getColumnNumber());
  1325. pushback(e);
  1326. __graph();
  1327. e = getNextEvent();
  1328. }
  1329. checkValid(e, XMLStreamConstants.END_ELEMENT, "edge");
  1330. }
  1331. /**
  1332. * <pre>
  1333. * <!ELEMENT hyperedge ((desc)?,((data)|(endpoint))*,(graph)?)>
  1334. * <!ATTLIST hyperedge
  1335. * id ID #IMPLIED
  1336. * >
  1337. * </pre>
  1338. *
  1339. * @throws IOException
  1340. * @throws XMLStreamException
  1341. */
  1342. private void __hyperedge() throws IOException, XMLStreamException {
  1343. XMLEvent e;
  1344. e = getNextEvent();
  1345. checkValid(e, XMLStreamConstants.START_ELEMENT, "hyperedge");
  1346. Location loc = e.getLocation();
  1347. System.err.printf("[WARNING] %d:%d hyperedge feature is not implemented", loc.getLineNumber(),
  1348. loc.getColumnNumber());
  1349. String id = null;
  1350. @SuppressWarnings("unchecked")
  1351. Iterator<? extends Attribute> attributes = e.asStartElement().getAttributes();
  1352. while (attributes.hasNext()) {
  1353. Attribute a = attributes.next();
  1354. try {
  1355. HyperEdgeAttribute attribute = HyperEdgeAttribute.valueOf(toConstantName(a));
  1356. switch (attribute) {
  1357. case ID:
  1358. id = a.getValue();
  1359. break;
  1360. }
  1361. } catch (IllegalArgumentException ex) {
  1362. throw newParseError(e, "invalid attribute '%s' for '<endpoint>'", a.getName().getLocalPart());
  1363. }
  1364. }
  1365. if (id == null)
  1366. throw newParseError(e, "'<hyperedge>' element requires a 'node' attribute");
  1367. e = getNextEvent();
  1368. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "desc")) {
  1369. pushback(e);
  1370. __desc();
  1371. } else {
  1372. while (isEvent(e, XMLStreamConstants.START_ELEMENT, "data") || isEvent(e, XMLStreamConstants.START_ELEMENT, "endpoint")) {
  1373. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "data")) {
  1374. pushback(e);
  1375. __data();
  1376. } else {
  1377. pushback(e);
  1378. __endpoint();
  1379. }
  1380. e = getNextEvent();
  1381. }
  1382. }
  1383. if (isEvent(e, XMLStreamConstants.START_ELEMENT, "graph")) {
  1384. loc = e.getLocation();
  1385. System.err.printf("[WARNING] %d:%d graph inside node is not implemented", loc.getLineNumber(),
  1386. loc.getColumnNumber());
  1387. pushback(e);
  1388. __graph();
  1389. e = getNextEvent();
  1390. }
  1391. e = getNextEvent();
  1392. checkValid(e, XMLStreamConstants.END_ELEMENT, "hyperedge");
  1393. }
  1394. }