-
Notifications
You must be signed in to change notification settings - Fork 1
/
7.17.go
61 lines (58 loc) · 1.34 KB
/
7.17.go
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
57
58
59
60
61
package main
import (
"encoding/xml"
"fmt"
"io"
"os"
"strings"
)
// fetch http://www.w3.org/TR/2006/REC-xml11-20060816 | ./ex7.17 toc h2
func main() {
dec := xml.NewDecoder(os.Stdin)
var stack [][]string // stack of element names and attributes
for {
tok, err := dec.Token()
if err == io.EOF {
break
} else if err != nil {
fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err)
os.Exit(1)
}
switch tok := tok.(type) {
case xml.StartElement:
nameAndAttributes := make([]string, 0)
nameAndAttributes = append(nameAndAttributes, tok.Name.Local)
for _, val := range tok.Attr {
if val.Name.Local == "id" || val.Name.Local == "class" {
nameAndAttributes = append(nameAndAttributes, val.Value)
}
}
stack = append(stack, nameAndAttributes) // push
case xml.EndElement:
stack = stack[:len(stack)-1] // pop
case xml.CharData:
if containsAll(stack, os.Args[1:]) {
for _, nameAndAttributes := range stack {
fmt.Printf("%s ", strings.Join(nameAndAttributes, "|"))
}
fmt.Printf(": %s\n", tok)
}
}
}
}
// containsAll reports whether x contains the elements of y, in order.
func containsAll(x [][]string, y []string) bool {
for len(y) <= len(x) {
if len(y) == 0 {
return true
}
for _, element := range x[0] {
if element == y[0] {
y = y[1:]
break
}
}
x = x[1:]
}
return false
}