001package com.ganteater.ae.util.xml.easyparser; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Map; 006import java.util.Set; 007import java.util.StringTokenizer; 008import java.util.Vector; 009 010import org.apache.commons.collections.map.LinkedMap; 011import org.apache.commons.lang.ObjectUtils; 012import org.apache.commons.lang.StringEscapeUtils; 013import org.apache.commons.lang.StringUtils; 014 015/** 016 * @author victort 017 */ 018public class Node extends ArrayList<Node> { 019 020 private static final String INDENT = "\t"; 021 022 private static final long serialVersionUID = 1L; 023 024 public static final String TEXT_TEAG_NAME = "$Text"; 025 026 public static final String TAG_ID = "$id"; 027 028 final static boolean debug = false; 029 030 protected int MAXATTRINLINE = 6; 031 032 protected final int SAMPLENODE = 0; 033 034 protected final int TEXNode = 1; 035 036 private String fTagName; 037 038 private Node fOwnerWriter = null; 039 040 private LinkedMap attributes = new LinkedMap(); 041 042 private boolean fNill = true; 043 044 private String fText; 045 046 private boolean fIgnoreSpaceInText = false; 047 048 public Node(String aTagName) { 049 fTagName = aTagName; 050 } 051 052 public Node(String tagName, Map<String, String> attributes, List<Node> nodes) { 053 this(tagName); 054 fTagName = tagName; 055 if (attributes != null) { 056 this.attributes = new LinkedMap(attributes); 057 } 058 if (nodes != null) { 059 for (int i = 0; i < nodes.size(); i++) { 060 Node theNode = (Node) nodes.get(i); 061 addInnerTag(theNode); 062 } 063 } 064 065 } 066 067 public boolean isNill() { 068 return fNill; 069 } 070 071 public void setNill(boolean aNill) { 072 fNill = aNill; 073 if (aNill) { 074 clear(); 075 } 076 } 077 078 @SuppressWarnings("unchecked") 079 public Map<String, String> getAttributes() { 080 return attributes; 081 } 082 083 public String getAttribute(String aName) { 084 return (String) attributes.get(aName); 085 } 086 087 public void setAttribute(String aName, String aValue) { 088 if (aName != null && aName.length() > 0 && Character.isLetter(aName.charAt(0))) { 089 attributes.put(aName, aValue); 090 } 091 } 092 093 public void setAttribute(String aName, boolean aValue) { 094 attributes.put(aName, aValue ? "true" : "false"); 095 } 096 097 public void setAttribute(String aName, long aValue) { 098 attributes.put(aName, Long.toString(aValue)); 099 } 100 101 public void setAttributes(Map<String, String> aAttributes) { 102 attributes = new LinkedMap(aAttributes); 103 } 104 105 public void setAttribute(String aName, double aValue) { 106 attributes.put(aName, Double.toString(aValue)); 107 } 108 109 public void removeAttribute(String name) { 110 attributes.remove(name); 111 } 112 113 public void removeAttributes() { 114 attributes.clear(); 115 } 116 117 protected void addInnerTag(Node aNode) { 118 if (aNode == this) { 119 throw new RuntimeException("Self inserting node."); 120 } 121 aNode.setOwner(this); 122 add(aNode); 123 } 124 125 protected void setOwner(Node aOwnerWriter) { 126 fOwnerWriter = aOwnerWriter; 127 } 128 129 protected int getLevel() { 130 if (fOwnerWriter == null) { 131 return 0; 132 } 133 return fOwnerWriter.getLevel() + 1; 134 } 135 136 private String getAttributeLine(int aLevel, String aKey) { 137 StringBuffer theBuffer = new StringBuffer(); 138 139 if (attributes.size() > MAXATTRINLINE) { 140 theBuffer.append(getFormatingTab(aLevel)); 141 } else { 142 theBuffer.append(' '); 143 } 144 145 theBuffer.append(aKey); 146 theBuffer.append("=\""); 147 148 String theValueOut = (String) attributes.get(aKey); 149 theValueOut = replace(theValueOut); 150 151 theBuffer.append(theValueOut); 152 theBuffer.append('\"'); 153 154 return theBuffer.toString(); 155 } 156 157 public static String replace(String aValueOut) { 158 if (aValueOut != null) { 159 // aValueOut = EasyParser.replaceProperties(aValueOut, "\"", """); 160 // aValueOut = EasyParser.replaceProperties(aValueOut, "\'", 161 // "'"); 162 aValueOut = EasyParser.replaceProperties(aValueOut, "<", "<"); 163 aValueOut = EasyParser.replaceProperties(aValueOut, ">", ">"); 164 } 165 return aValueOut; 166 } 167 168 public String getXMLText() { 169 if (fText != null) { 170 return fText; 171 } 172 if (TEXT_TEAG_NAME.equals(fTagName)) { 173 return new String(); 174 } 175 176 if (debug) { 177 System.out.println("-- getXMLText()"); 178 } 179 180 String text = getXMLText(0); 181 182 return text; 183 } 184 185 protected String getXMLText(int aLevel) { 186 if (fText != null) { 187 return getXMLText(); 188 } 189 if (TEXT_TEAG_NAME.equals(fTagName)) { 190 return new String(); 191 } 192 193 if (debug) { 194 System.out.println("-- getXMLText( int aLevel )"); 195 } 196 197 aLevel++; 198 199 StringBuffer theBuffer = new StringBuffer(); 200 201 theBuffer.append(getFormatingTab(aLevel)); 202 203 if ("Comment".equals(fTagName) == false) { 204 theBuffer.append('<'); 205 theBuffer.append(fTagName); 206 207 if (attributes.size() > 0) { 208 @SuppressWarnings("unchecked") 209 Set<String> theEnumKey = attributes.keySet(); 210 211 for (String name : theEnumKey) { 212 if (attributes.size() > MAXATTRINLINE) { 213 theBuffer.append("\r\n"); 214 } 215 theBuffer.append(getAttributeLine(aLevel, name)); 216 } 217 } 218 219 if (size() == 0) { 220 theBuffer.append(" />"); 221 } else { 222 theBuffer.append('>'); 223 224 if ((size() > 0 || attributes.size() > MAXATTRINLINE) 225 && TEXT_TEAG_NAME.equals(getNode(0).getTag()) == false) { 226 theBuffer.append("\r\n"); 227 } 228 229 for (int theCurrent = 0; theCurrent < size(); theCurrent++) { 230 if (debug) { 231 System.out.println("-- getXMLText( int aLevel ) for ( int theCurrent... "); 232 } 233 theBuffer.append(getInnerXMLText(aLevel, theCurrent)); 234 } 235 236 if (TEXT_TEAG_NAME.equals(getNode(0).getTag()) == false) { 237 theBuffer.append(getFormatingTab(aLevel)); 238 } 239 240 theBuffer.append("</"); 241 theBuffer.append(fTagName); 242 theBuffer.append('>'); 243 } 244 } else { 245 theBuffer.append("<!--"); 246 for (int theCurrent = 0; theCurrent < size(); theCurrent++) { 247 theBuffer.append(getInnerXMLText(aLevel, theCurrent).replaceAll("<", "<").replaceAll(">", ">") 248 .replaceAll("&", "&").replaceAll(""", "\"").replaceAll("'", "\'")); 249 } 250 theBuffer.append("-->"); 251 } 252 253 theBuffer.append(" \r\n"); 254 return theBuffer.toString(); 255 } 256 257 private String getFormatingTab(int aLevel) { 258 StringBuffer theBuffer = new StringBuffer(); 259 for (int theTab = 1; theTab < aLevel; theTab++) { 260 theBuffer.append(INDENT); 261 } 262 return theBuffer.toString(); 263 } 264 265 private String getInnerXMLText(int aLevel, int theInnerTag) { 266 Node theNode = (Node) get(theInnerTag); 267 return theNode.getXMLText(aLevel); 268 } 269 270 public String getTag() { 271 return fTagName; 272 } 273 274 public Node[] getNodes(String aTag) { 275 if (aTag.indexOf("*/") == 0) { 276 return new Node[] { findNode(aTag.substring(2), null, null) }; 277 } 278 279 if (aTag.indexOf("/") > 0) { 280 return getNodesPatch(aTag); 281 } 282 283 int theNumberNode = size(); 284 285 List<Node> theResultArrayList = new ArrayList<>(); 286 287 for (int i = 0; i < theNumberNode; i++) { 288 Node theCurrenNode = (Node) get(i); 289 String theTagName = theCurrenNode.getTag(); 290 int theLengPreffix = theTagName.indexOf(':'); 291 if (theLengPreffix >= 0) { 292 theTagName = theTagName.substring(theLengPreffix + 1); 293 } 294 if (theTagName.equals(aTag)) { 295 theResultArrayList.add(theCurrenNode); 296 } 297 } 298 299 Node[] theResult = new Node[theResultArrayList.size()]; 300 for (int i = 0; i < theResultArrayList.size(); i++) { 301 theResult[i] = (Node) theResultArrayList.get(i); 302 } 303 304 return theResult; 305 } 306 307 private Node[] getNodesPatch(String aPatch) { 308 StringTokenizer theStringTokenizer = new StringTokenizer(aPatch, "/"); 309 310 Node theCurrenNode = this; 311 Node[] theResult = null; 312 313 while (theStringTokenizer.hasMoreTokens()) { 314 theResult = theCurrenNode.getNodes(theStringTokenizer.nextToken()); 315 if (theResult != null && theResult.length > 0) { 316 theCurrenNode = theResult[0]; 317 } 318 } 319 320 return theResult; 321 } 322 323 public void setText(String aText) { 324 325 aText = replace(aText); 326 327 if (fIgnoreSpaceInText) { 328 StringBuffer theBuffer = null; 329 StringTokenizer theTokenizer = new StringTokenizer(aText, " \n\r"); 330 theBuffer = new StringBuffer(); 331 boolean theFirstToken = true; 332 while (theTokenizer.hasMoreTokens()) { 333 if (theFirstToken) { 334 theFirstToken = false; 335 } else { 336 theBuffer.append(' '); 337 } 338 339 theBuffer.append(theTokenizer.nextToken()); 340 } 341 fText = theBuffer.toString(); 342 } else { 343 fText = aText; 344 } 345 } 346 347 public String getText() { 348 return StringEscapeUtils.unescapeXml(fText); 349 } 350 351 public Node findNode(String aTagName, String aAttributeName, String aAttributeValue) { 352 int theNumberNode = size(); 353 354 String tag = getTag(); 355 int prefixpoint = tag.indexOf(':'); 356 if (prefixpoint >= 0) { 357 tag = tag.substring(prefixpoint + 1); 358 } 359 360 String theAttribut = null; 361 if (aAttributeName != null) { 362 theAttribut = getAttribute(aAttributeName); 363 } 364 365 if (aTagName == null || tag.equals(aTagName)) { 366 if (aAttributeName != null) { 367 if (ObjectUtils.equals(theAttribut, aAttributeValue)) { 368 return this; 369 } 370 } else { 371 return this; 372 } 373 } 374 375 for (int i = 0; i < theNumberNode; i++) { 376 Node theCurrenNode = (Node) get(i); 377 Node node = theCurrenNode.findNode(aTagName, aAttributeName, aAttributeValue); 378 if (node != null) { 379 return node; 380 } 381 } 382 383 return null; 384 } 385 386 public Node[] findNodes(String tagName, String attributeName, String attributeValue) { 387 int theNumberNode = size(); 388 389 Vector<Node> noresVector = new Vector<>(); 390 391 for (int i = 0; i < theNumberNode; i++) { 392 Node node = (Node) get(i); 393 394 String value = node.getAttribute(attributeName); 395 396 if (StringUtils.equals(node.getTag(), tagName) 397 && (StringUtils.equals(value, attributeValue) || attributeName == null)) { 398 noresVector.add(node); 399 } 400 401 Node[] nodes = node.findNodes(tagName, attributeName, attributeValue); 402 for (int j = 0; j < nodes.length; j++) { 403 noresVector.add(nodes[j]); 404 } 405 } 406 407 Node[] result = new Node[noresVector.size()]; 408 for (int i = 0; i < result.length; i++) { 409 result[i] = (Node) noresVector.get(i); 410 } 411 412 return result; 413 } 414 415 public void setTag(String aTagName) { 416 fTagName = aTagName; 417 } 418 419 public Node getNode(int i) { 420 return (Node) get(i); 421 } 422 423 public void removeNode(String theAttributeName, String theAttributeValue) { 424 removeNode(this, theAttributeName, theAttributeValue); 425 } 426 427 private void removeNode(Node aNode, String theAttributeName, String theAttributeValue) { 428 for (int i = 0; i < aNode.size(); i++) { 429 Node theCurrentNode = (Node) aNode.get(i); 430 String theAttribut = theCurrentNode.getAttribute(theAttributeName); 431 if (theAttribut != null && theAttribut.equals(theAttributeValue)) { 432 aNode.remove(i); 433 return; 434 } else { 435 removeNode(theCurrentNode, theAttributeName, theAttributeValue); 436 } 437 } 438 } 439 440 class TagCounter { 441 public int number = 0; 442 443 public int getNumber() { 444 return number++; 445 } 446 } 447 448 public TreeVector getVector() { 449 TreeVector o = (TreeVector) nodeHashtables(this, null, false); 450 if (o == null) { 451 o = new TreeVector(); 452 } 453 454 return o; 455 } 456 457 public TreeVector getVector(boolean withId) { 458 TreeVector hashtable = new TreeVector(); 459 TagCounter numberCommand = null; 460 if (withId) 461 numberCommand = new TagCounter(); 462 463 Object o = nodeHashtables(this, numberCommand, withId); 464 if (o == null) { 465 o = new Vector<Object>(); 466 } 467 hashtable.add(o); 468 469 return hashtable; 470 } 471 472 private Object nodeHashtables(Node aNode, TagCounter commandId, boolean removeId) { 473 TreeVector hashtable = new TreeVector(); 474 475 Node key = aNode; 476 477 int number = -1; 478 479 if (commandId != null) 480 number = commandId.getNumber(); 481 482 if (TEXT_TEAG_NAME.equals(aNode.getTag()) == false) { 483 if (number > 0) 484 key.setAttribute(TAG_ID, number); 485 486 Node node = new Node(aNode.getTag()); 487 @SuppressWarnings("unchecked") 488 Map<String, String> attributes = new LinkedMap(aNode.getAttributes()); 489 490 if (removeId) { 491 attributes.remove(TAG_ID); 492 } 493 494 node.setAttributes(attributes); 495 String s = node.getXMLText().replace('\n', ' ').trim(); 496 if (s.length() > 0) { 497 s = s.substring(1, s.length() - 3); 498 } 499 500 hashtable.setNode(aNode); 501 hashtable.setTitle(s); 502 503 int numberNodes = aNode.size(); 504 505 for (int i = 0; i < numberNodes; i++) { 506 hashtable.addElement(nodeHashtables((Node) aNode.get(i), commandId, removeId)); 507 } 508 509 } else { 510 String text = aNode.getText(); 511 512 if (text != null) { 513 return text; 514 } else { 515 return '<' + aNode.getTag() + "/>"; 516 } 517 } 518 519 return hashtable; 520 } 521 522 public static class TreeVector extends Vector<Object> { 523 private static final long serialVersionUID = 1L; 524 525 private String fTitle; 526 private Node node; 527 528 public TreeVector(String text) { 529 fTitle = text; 530 } 531 532 public TreeVector() { 533 } 534 535 public synchronized String toString() { 536 return fTitle; 537 } 538 539 public void setNode(Node node) { 540 this.node = node; 541 } 542 543 public void setTitle(String title) { 544 fTitle = title; 545 } 546 547 public Node getNode() { 548 return node; 549 } 550 } 551 552 @Override 553 public String toString() { 554 return getXMLText(); 555 } 556 557 public Node[] getTextNodes() { 558 return getNodes(TEXT_TEAG_NAME); 559 } 560 561 public String getInnerText() { 562 Node[] nodes = getTextNodes(); 563 if (nodes.length > 0) { 564 return nodes[0].getText(); 565 } 566 return StringUtils.EMPTY; 567 } 568 569 public String getInnerXMLText() { 570 StringBuilder xml = new StringBuilder(); 571 for (Node node : this) { 572 xml.append(node.getXMLText()); 573 xml.append('\n'); 574 } 575 return xml.toString(); 576 } 577 578 @Override 579 public Node clone() { 580 Node clone = new Node(getTag()); 581 clone.setAttributes(getAttributes()); 582 clone.addAll(this); 583 return clone; 584 } 585}