1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.util.Scanner;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
 
/** A Scanner-like class that reads XML open and close tags.
 */
public class TagScanner {
  /** The regular expression to match a complete tag. */
  private static Pattern tagPat = Pattern.compile("<(/?)(\\w+)\\s*>");
 
  /** The regular expression to match any text that starts with some tag. */
  private static Pattern startTag = Pattern.compile("\\s*</?\\w+\\s*>.*");
 
  /** The underlying Scanner object that will be used to read. */
  private Scanner scan;
 
  /** Creates a new TagScanner from System.in. */
  public TagScanner() {
    this.scan = new Scanner(System.in);
  }
 
  /** Matches the java.util.Scanner constructor. */
  public TagScanner(java.io.File source) throws java.io.FileNotFoundException
    { this.scan = new Scanner(source); }
  /** Matches the java.util.Scanner constructor. */
  public TagScanner(java.io.InputStream source) { this.scan = new Scanner(source); }
  /** Matches the java.util.Scanner constructor. */
  public TagScanner(Readable source) { this.scan = new Scanner(source); }
  /** Matches the java.util.Scanner constructor. */
  public TagScanner(String source) { this.scan = new Scanner(source); }
 
  /** Returns the underlying Scanner instance.
   * You could use this if you\'d like to read something that\'s not
   * a tag from the same source.
   */
  public Scanner getScanner() { return scan; }
 
  /** Returns true if there is another XML tag in the input. */
  public boolean hasNext() {
    return scan.hasNext(startTag);
  }
 
  /** Returns the Tag object for the next XML tag in the input stream.
   * @throws NoSuchElementException if the next token is not an XML tag.
   */
  public Tag next() {
    String fullMatch = scan.findWithinHorizon(tagPat, 0);
    if (fullMatch == null) throw new NoSuchElementException("No tag in scanner");
    Matcher tagMatcher = tagPat.matcher(fullMatch);
    boolean didMatch = tagMatcher.matches();
    assert didMatch;
    boolean open = tagMatcher.group(1).equals("");
    return new Tag(tagMatcher.group(2), open, !open);
  }
}