skipToPath

Treats the given string like a file path except that each directory corresponds to the name of a start tag. Note that this does not try to implement XPath as that would be quite complicated, and it really doesn't fit with a StAX parser.

A start tag should be thought of as a directory, with its child start tags as the directories it contains.

All paths should be relative. EntityRange can only move forward through the document, so using an absolute path would only make sense at the beginning of the document. As such, absolute paths are treated as invalid paths.

"./" and "../" are supported. Repeated slashes such as in "foo//bar" are not supported and are treated as an invalid path.

If range.front.type == EntityType.elementStart, then range._skiptoPath($(D_STRING "foo")) will search for the first child start tag (be it EntityType.elementStart or EntityType.elementEmpty) with the name "foo". That start tag must be a direct child of the current start tag.

If range.front.type is any other EntityType, then range._skipToPath($(D_STRING "foo")) will return an empty range, because no other EntityTypes have child start tags.

For any EntityType, range._skipToPath($(D_STRING "../foo")) will search for the first start tag with the name "foo" at the same level as the current entity. If the current entity is a start tag with the name "foo", it will not be considered a match.

range._skipToPath($(D_STRING "./")) is a no-op. However, range._skipToPath($(D_STRING "../")) will result in the empty range (since it doesn't target a specific start tag).

range._skipToPath($(D_STRING "foo/bar")) is equivalent to range._skipToPath($(D_STRING "foo"))._skipToPath($(D_STRING "bar")), and range._skipToPath($(D_STRING "../foo/bar")) is equivalent to range._skipToPath($(D_STRING "../foo"))._skipToPath($(D_STRING "bar")).

R
skipToPath
(
R
)
(,
string path
)
if (
isInstanceOf!(EntityRange, R)
)

Return Value

Type: R

The given range with its front now at the requested entity if the path is valid; otherwise, an empty range is returned.

Throws

XMLParsingException on invalid XML.

Examples

1 {
2     auto xml = "<carrot>\n" ~
3                "    <foo>\n" ~
4                "        <bar>\n" ~
5                "            <baz/>\n" ~
6                "            <other/>\n" ~
7                "        </bar>\n" ~
8                "    </foo>\n" ~
9                "</carrot>";
10 
11     auto range = parseXML(xml);
12     // "<carrot>"
13     assert(range.front.type == EntityType.elementStart);
14     assert(range.front.name == "carrot");
15 
16     range = range.skipToPath("foo/bar");
17     // "        <bar>
18     assert(!range.empty);
19     assert(range.front.type == EntityType.elementStart);
20     assert(range.front.name == "bar");
21 
22     range = range.skipToPath("baz");
23     // "            <baz/>
24     assert(!range.empty);
25     assert(range.front.type == EntityType.elementEmpty);
26 
27     // other is not a child element of baz
28     assert(range.skipToPath("other").empty);
29 
30     range = range.skipToPath("../other");
31     // "            <other/>"
32     assert(!range.empty);
33     assert(range.front.type == EntityType.elementEmpty);
34 }
35 {
36     auto xml = "<potato>\n" ~
37                "    <foo>\n" ~
38                "        <bar>\n "~
39                "        </bar>\n" ~
40                "        <crazy>\n" ~
41                "        </crazy>\n" ~
42                "        <fou/>\n" ~
43                "    </foo>\n" ~
44                "    <buzz/>\n" ~
45                "</potato>";
46 
47     auto range = parseXML(xml);
48     // "<potato>"
49     assert(range.front.type == EntityType.elementStart);
50 
51     range = range.skipToPath("./");
52     // "<potato>"
53     assert(!range.empty);
54     assert(range.front.type == EntityType.elementStart);
55     assert(range.front.name == "potato");
56 
57     range = range.skipToPath("./foo/bar");
58     // "        <bar>"
59     assert(!range.empty);
60     assert(range.front.type == EntityType.elementStart);
61     assert(range.front.name == "bar");
62 
63     range = range.skipToPath("../crazy");
64     // "        <crazy>"
65     assert(!range.empty);
66     assert(range.front.type == EntityType.elementStart);
67     assert(range.front.name == "crazy");
68 
69     // Whether popFront is called here before the call to
70     // range.skipToPath("../fou") below, the result is the same, because
71     // both <crazy> and </crazy> are at the same level.
72     range.popFront();
73     // "        </crazy>"
74     assert(!range.empty);
75     assert(range.front.type == EntityType.elementEnd);
76     assert(range.front.name == "crazy");
77 
78     range = range.skipToPath("../fou");
79     // "        <fou/>"
80     assert(!range.empty);
81     assert(range.front.type == EntityType.elementEmpty);
82 }
83 // Searching stops at the first matching start tag.
84 {
85     auto xml = "<beet>\n" ~
86                "    <foo a='42'>\n" ~
87                "    </foo>\n" ~
88                "    <foo b='451'>\n" ~
89                "    </foo>\n" ~
90                "</beet>";
91 
92     auto range = parseXML(xml);
93     range = range.skipToPath("foo");
94     assert(!range.empty);
95     assert(range.front.type == EntityType.elementStart);
96     assert(range.front.name == "foo");
97 
98     {
99         auto attrs = range.front.attributes;
100         assert(attrs.front.name == "a");
101         assert(attrs.front.value == "42");
102     }
103 
104     range = range.skipToPath("../foo");
105     assert(!range.empty);
106     assert(range.front.type == EntityType.elementStart);
107     assert(range.front.name == "foo");
108 
109     {
110         auto attrs = range.front.attributes;
111         assert(attrs.front.name == "b");
112         assert(attrs.front.value == "451");
113     }
114 }
115 // skipToPath will work on an empty range but will always return an
116 // empty range.
117 {
118     auto range = parseXML("<root/>");
119     assert(range.takeNone().skipToPath("nowhere").empty);
120 }
121 // Empty and absolute paths will also result in an empty range as will
122 // "../" without any actual tag name on the end.
123 {
124     auto range = parseXML("<root/>");
125     assert(range.skipToPath("").empty);
126     assert(range.skipToPath("/").empty);
127     assert(range.skipToPath("../").empty);
128 }
129 // Only non-empty start tags have children; all other EntityTypes result
130 // in an empty range unless "../" is used.
131 {
132     auto xml = "<!-- comment -->\n" ~
133                "<root>\n" ~
134                "    <foo/>\n" ~
135                "</root>";
136     auto range = parseXML(xml);
137     assert(range.skipToPath("root").empty);
138     assert(range.skipToPath("foo").empty);
139 
140     range = range.skipToPath("../root");
141     assert(!range.empty);
142     assert(range.front.type == EntityType.elementStart);
143     assert(range.front.name == "root");
144 }

Meta