import java.util.*; import java.io.*; import static java.lang.System.out; import java.nio.file.*; import java.nio.file.StandardCopyOption; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author Divine Welcome to my Halo 2 XML Parsing program This program parses all matches in your 'stats' folder, and uses player data to build a static html leaderboard table. Subsequent runs of the program read from the html file and use it to rebuild the leaderboard data structure -- and add any new information from subsequent matches. Matches which have already been parsed will be placed into the 'parsed' folder. The statsfolder, parsed folder, and output file can all be toggled in config.ini -- write them in that order, line by line --using absolute paths for the first two and a file name with an htm or html extension for the last. */ public class XmlParser { /** * @param args the command line arguments */ public static boolean verbose = false; public static boolean excessive= false; public static final int OPEN_TAGS = 2; public static final int CLOSE_TAGS = 3; public static final int OPEN_DATA = 4; public static final int CLOSE_DATA = 5; public static final int MOD = 7; private static Map leaderboard = new TreeMap<>(); private static String statsFolder; private static String parsedFolder; private static Scanner configScanner; public static final File config = new File("config.ini"); private static File leaderboardFile; public static final String DEFAULT_OUTPUT_FILE = "index.html"; private static String outputFile; public static void main(String[] args)throws FileNotFoundException, IOException { /*commandline options*/ for(int i = 0; i < args.length; i++) { switch(args[i]) { case "-h": help(); /*exits*/ break; case "-e": excessive(); break; case "-v": verbose(); break; case "-version": version(); break; default: out.println("ignoring unrecognized commandline option"); break; } } configCheck(); directoryCheck(); File folder = new File(statsFolder); String[] files = folder.list(); if(leaderboardFile.exists() & files.length > 0) { build(); } if(files.length > 0) { scanFilesUpdateLeaderboard(files); createHTML(outputFile); } else { out.println("no files to parse"); } } public static void help() { out.println("Hi welcome to my XML parsing program for Halo 2 Vista stats!"); out.println("verbose output logs the files parsed to the console"); out.println("excessive output logs the player stats parsed to the console"); out.println("this is the help menu : P "); out.println("this program only recognizes 1 commandline option at a time; excessive is"); out.println("just the verbose output plus all the player stats"); out.println("use the verbose or excessive output options only if there are strange things"); out.println("happening when parsing your xml --or if you want something to watch while waiting lol"); out.println("this program is fastest when run with no options though ;)"); out.println("The config file should have 3 lines"); out.println("the first is the absolute path to your statsfolder"); out.println("the second is the absolute path to your parsed folder"); out.println("i.e. the folder where already parsed matches will be placed"); out.println("and the 3rd, is the output file -- must have a .html or .htm extension"); out.println("the program reads past data from the html file and updates it with new matches in"); out.println("the stats folder -- I recommend putting this program on the task scheduler"); System.exit(0); } public static void excessive() { out.println("using excessive output"); excessive = true; verbose = true; } public static void verbose() { out.println("using verbose output"); verbose = true; } public static void version() { out.println("Release version 0.5"); System.exit(0); } public static void configCheck() throws FileNotFoundException{ if(config.exists()) { out.println("reading config..."); configScanner = new Scanner(config); /*Format is stasfolder on line 1, parsedFolder on line 2*/ if(configScanner.hasNextLine()) { statsFolder = configScanner.nextLine().trim(); } else { configExit(); } if(configScanner.hasNextLine()) { parsedFolder = configScanner.nextLine().trim(); } else { configExit(); } if(configScanner.hasNextLine()) { outputFile = configScanner.nextLine().trim(); leaderboardFile = new File(outputFile); } } else { out.println("using default config... C:/stats & C:/parsed\ncreating config.ini..."); defaultConfig(); } configScanner.close(); } public static void configExit() { out.println("make sure to fill out the config:\nline 1 is statsfolder, line 2 is parsed files folder"); out.println("exiting..."); System.exit(0); } public static void defaultConfig() throws FileNotFoundException{ statsFolder = "C:/stats/"; parsedFolder= "C:/parsed/"; PrintStream printConfig = new PrintStream(config); printConfig.println(statsFolder); printConfig.println(parsedFolder); printConfig.println(DEFAULT_OUTPUT_FILE); printConfig.close(); } public static void directoryCheck() { try { Path stats = Files.createDirectory(Paths.get(statsFolder)); } catch(FileAlreadyExistsException e){ out.println("found statsFolder located at " + statsFolder); } catch (IOException e) { //something else went wrong e.printStackTrace(); System.exit(0); } try { Path parsed = Files.createDirectory(Paths.get(parsedFolder)); } catch(FileAlreadyExistsException e){ out.println("found parsedFolder located at " + parsedFolder); } catch (IOException e) { //something else went wrong e.printStackTrace(); System.exit(0); } } public static void build() throws FileNotFoundException{ out.println("building list from table..."); buildList(); } public static void buildList() throws FileNotFoundException{ Scanner input = new Scanner(leaderboardFile); int lineNumber = 0; int dataLine = 0; String Name = ""; int Kills = 0; int Assists = 0; int Deaths = 0; /*out.println("about to enter loop");*/ while(input.hasNextLine()) { String line = input.nextLine().trim(); /*out.println(line);*/ if(!line.contains("")){ if(lineNumber == 17) { dataLine = 0; } if((dataLine % MOD) == 0 & lineNumber >= 17) { Name = extractData(line, "td"); /*out.println("setting name = " + Name);*/ } else if((dataLine % MOD) == 1 & lineNumber >= 17) { Kills = Integer.parseInt(extractData(line,"td")); /*out.println("setting kills =" + Kills);*/ } else if((dataLine % MOD) == 2 & lineNumber >= 17) { Assists = Integer.parseInt(extractData(line,"td")); /*out.println("setting Assists =" + Assists);*/ } else if((dataLine % MOD) == 3 & lineNumber >= 17) { Deaths = Integer.parseInt(extractData(line,"td")); leaderboard.put(Name,new Player(Name,Kills,Assists,Deaths)); /*out.println("setting Deaths ="+ Deaths);*/ } lineNumber++; dataLine++; } else { break; } } input.close(); } public static void scanFilesUpdateLeaderboard(String [] files) throws FileNotFoundException{ out.println("run with argument '-v' for verbose output, '-e' for excessive, or -h for more help"); out.println("Reading files..."); out.println("parsing " + files.length + " files"); Scanner input; for(String s: files) { String currentPath = statsFolder + s; String parsedPath = parsedFolder + s; File currentFile = new File(currentPath); input = new Scanner(currentFile); if(verbose) {out.println("Reading File: " + s);} String Name = ""; int Kills = 0; int Assists = 0; int Deaths = 0; while(input.hasNextLine()) { String line = input.nextLine().trim(); if(containsData(line, "Name")) { Name = extractData(line, "Name"); if(excessive) {out.print(Name + ", ");} } else if(containsData(line, "Kills")) { Kills = Integer.parseInt(extractData(line,"Kills")); if(excessive) {out.print(Kills + ", ");} } else if(containsData(line, "Assists")) { Assists = Integer.parseInt(extractData(line,"Assists")); if(excessive) {out.print(Assists +", ");} } else if(containsData(line, "Deaths")) { Deaths = Integer.parseInt(extractData(line,"Deaths")); if(excessive) {out.println(Deaths);} if (!leaderboard.keySet().contains(Name)) { leaderboard.put(Name,new Player(Name,Kills,Assists,Deaths)); } else { Player tPlayer = leaderboard.get(Name); tPlayer.addKills(Kills); tPlayer.addAssists(Assists); tPlayer.addDeaths(Deaths); } } } input.close(); try { Files.move(Paths.get(currentPath), Paths.get(parsedPath), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { //moving file failed. e.printStackTrace(); out.println("Make sure to set your parsed folder in the config!"); out.println("that is where parsed files will go; default is C:/parsed"); System.exit(0); } } } public static boolean containsData(String line, String tag) { return line.contains("<"+tag+">"); } public static String extractData(String line, String tag) { return line.substring(tag.length() + OPEN_TAGS, line.length() - (tag.length() + CLOSE_TAGS)).trim(); //removes the opening & closing tags to extract data } public static void createHTML(String htmlFileName) throws FileNotFoundException { Set sortedBoard = new TreeSet<>(); PrintStream table = new PrintStream(htmlFileName); int count = 1; for(String s: leaderboard.keySet()) { sortedBoard.add(leaderboard.get(s)); count++; } /*html initialization*/ table.print("\n" + "\n" + "\n" + "\n" + "

Divine's Leaderboard


\n" + "

" + "Number of Unique Gamertags: " + (count - 1) + "

\n" + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n"); int rank = 1; for(Player p: sortedBoard) { table.printf("\n\n\n\n\n\n\n",rank,p.getName(), p.getKills(), p.getAssists(), p.getDeaths()); rank++; } table.printf("
RankNameKillsAssistsDeaths
%d%20s%-10d%10d%-10d
\n" + "\n" + "\n" + ""); table.close(); out.println("Finished"); } }