├── test
├── 1.php
└── 1.xml
├── LICENSE.md
├── benchmark
├── index.php
└── sample_100.xml
├── README.md
└── xml.php
/test/1.php:
--------------------------------------------------------------------------------
1 | data);
7 |
8 | ?>
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Marat A. Denenberg
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/benchmark/index.php:
--------------------------------------------------------------------------------
1 | children() as $elementName => $node)
8 | {
9 | $nextIdx = count($arr);
10 | $arr[$nextIdx] = [
11 | '@name' => strtolower((string)$elementName),
12 | '@attributes' => [],
13 | '@children' => [],
14 | '@text' => trim((string)$node)
15 | ];
16 | foreach($node->attributes() as $attributeName => $attributeValue)
17 | {
18 | $arr[$nextIdx]['@attributes'][strtolower(
19 | trim((string)$attributeName)
20 | )] = trim((string)$attributeValue);
21 | }
22 | convertSimpleXmlObjToArr($node, $arr[$nextIdx]['@children']);
23 | }
24 | }
25 |
26 | $path = dirname(__FILE__) . DIRECTORY_SEPARATOR;
27 | foreach(
28 | [
29 | 'simplexml' => [
30 | '100' => "{$path}sample_100.xml",
31 | '10000' => "{$path}sample_10000.xml"
32 | ],
33 | 'xml' => [
34 | '100' => "{$path}sample_100.xml",
35 | '10000' => "{$path}sample_10000.xml"
36 | ]
37 | ]
38 | as
39 | $type => $files
40 | )
41 | {
42 | foreach($files as $lines => $file)
43 | {
44 | $samples = [];
45 | for($i = 0; $i < 32; $i++)
46 | {
47 | $start = microtime(true);
48 | switch($type)
49 | {
50 | case 'simplexml':
51 | $sxe = new SimpleXMLElement($file, null, true);
52 | $arr = [];
53 | convertSimpleXmlObjToArr($sxe, $arr);
54 | unset($sxe, $arr);
55 | break;
56 |
57 | case 'xml':
58 | $xml = new xml($file);
59 | $arr = $xml->data;
60 | unset($xml, $arr);
61 | break;
62 | }
63 | $samples[] = microtime(true) - $start;
64 | }
65 | echo "{$type}: Parsed {$lines} line xml file in " .
66 | number_format((array_sum($samples) / 32), 4) .
67 | " seconds.\n";
68 | }
69 | }
70 |
71 | ?>
--------------------------------------------------------------------------------
/benchmark/sample_100.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Belgian Waffles
5 | $5.95
6 | Two of our famous Belgian Waffles with plenty of real maple syrup.
7 |
8 |
9 |
10 | Strawberry Belgian Waffles
11 | $7.95
12 | Light Belgian waffles covered with strawberries and whipped cream.
13 | 900
14 |
15 |
16 | Waffles
17 |
18 |
19 | Belgian Waffles
20 | $5.95
21 | Two of our famous Belgian Waffles with plenty of real maple syrup.
22 |
23 |
24 |
25 | Strawberry Belgian Waffles
26 | $7.95
27 | Light Belgian waffles covered with strawberries and whipped cream.
28 | 900
29 |
30 |
31 | Waffles
32 |
33 |
34 | Belgian Waffles
35 | $5.95
36 | Two of our famous Belgian Waffles with plenty of real maple syrup.
37 |
38 |
39 |
40 | Strawberry Belgian Waffles
41 | $7.95
42 | Light Belgian waffles covered with strawberries and whipped cream.
43 | 900
44 |
45 |
46 | Waffles
47 |
48 |
49 | Belgian Waffles
50 | $5.95
51 | Two of our famous Belgian Waffles with plenty of real maple syrup.
52 |
53 |
54 |
55 | Strawberry Belgian Waffles
56 | $7.95
57 | Light Belgian waffles covered with strawberries and whipped cream.
58 | 900
59 |
60 |
61 | Waffles
62 |
63 |
64 | Belgian Waffles
65 | $5.95
66 | Two of our famous Belgian Waffles with plenty of real maple syrup.
67 |
68 |
69 |
70 | Strawberry Belgian Waffles
71 | $7.95
72 | Light Belgian waffles covered with strawberries and whipped cream.
73 | 900
74 |
75 |
76 | Waffles
77 |
78 |
79 | Belgian Waffles
80 | $5.95
81 | Two of our famous Belgian Waffles with plenty of real maple syrup.
82 |
83 |
84 |
85 | Strawberry Belgian Waffles
86 | $7.95
87 | Light Belgian waffles covered with strawberries and whipped cream.
88 | 900
89 |
90 |
91 | Waffles
92 |
93 |
94 | Belgian Waffles
95 | $5.95
96 | Two of our famous Belgian Waffles with plenty of real maple syrup.
97 |
98 |
99 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP XML Parser
2 |
3 | A PHP XML parser class that provides an easy way to convert XML into native PHP
4 | arrays and back again. It has no dependencies on any external libraries or
5 | extensions bundled with PHP. The entire parser is concisely written in PHP.
6 |
7 | This project is actively maintained. It is used in our production code. If you
8 | spot an issue, please let us know through the Issues section on our Github
9 | project page: https://github.com/revnode/xml/issues
10 |
11 | ## Why
12 |
13 | As XML becomes less popular, the need for a parser moves from constant to
14 | infrequent. It makes little sense to keep a parser resident in memory at all times
15 | for functionality that might be used once every few days.
16 |
17 | For example, just to get SimpleXML going, you will need to have the libxml2
18 | library installed on your system. You will need xml, libxml, and simplexml
19 | extensions installed for PHP. You will need to keep all those extensions in
20 | memory for each request.
21 |
22 | In contrast, this simple parser is less than 500 lines of code and is only
23 | loaded when you need it. It has no dependencies, no required libraries or
24 | extensions, and will work on any modern PHP installation. The price you pay for
25 | that convenience is speed. It is much slower than SimpleXML. See the benchmarking
26 | section for details.
27 |
28 | In short, this project makes sense for those who want to simplify their PHP
29 | install and use, have a need for a simple XML parser, but don't much care
30 | about speed.
31 |
32 | ## Requirements
33 |
34 | PHP 5.4.0+
35 |
36 | ## Install
37 |
38 | Just place the xml.php file in a convenient location and include it in your
39 | code.
40 |
41 | ## Design Goals
42 |
43 | * Zero dependencies on external libraries or PHP extensions.
44 | * Provide a parser from and to the XML standard.
45 | * Provide support for the most commonly used parts of the XML standard.
46 | * Maintain a minimal memory footprint during operation, even for large XML files.
47 | * Maintain a codebase that is less than 1000 lines. Currently at less than 500 lines.
48 |
49 | ## Usage
50 |
51 | ### XML String to PHP Array
52 |
53 | ```php
54 |
59 |
60 |
61 | Waffles
62 |
63 | ');
64 | var_dump($xml->data);
65 |
66 | ?>
67 | ```
68 |
69 | ### XML File to PHP Array
70 |
71 | ```php
72 | data);
78 |
79 | ?>
80 | ```
81 |
82 | ### PHP Array to XML String
83 |
84 | ```php
85 | [
91 | [
92 | 'food' => [
93 | 'name' => 'Waffles'
94 | ]
95 | ]
96 | ]
97 | ]);
98 | echo $xml;
99 |
100 | ?>
101 | ```
102 |
103 | ## Benchmarks
104 |
105 | A benchmark to measure memory performance for large xml files is on the todo list.
106 |
107 | The following is the result of the benchmark code executing. The code is executed
108 | 32 times and then averaged. The code was run on an Intel(R) Atom(TM) CPU D510
109 | @ 1.66GHz with 4GB of RAM.
110 |
111 | ```
112 | simplexml: Parsed 100 line xml file in 0.0033 seconds.
113 | simplexml: Parsed 10000 line xml file in 2.0063 seconds.
114 | xml: Parsed 100 line xml file in 0.0251 seconds.
115 | xml: Parsed 10000 line xml file in 11.8074 seconds.
116 | ```
117 |
118 | For small files, the simplexml parser is almost 8 times faster. For larger files,
119 | it is 6 times faster.
120 |
121 | This is a signficant performance difference. However, if you're using the code
122 | on a file that's not that large, even with the performance degradation, the job
123 | will finish within a fraction of a second.
124 |
125 | ## Tests
126 |
127 | None, for now.
128 |
129 | ## License
130 |
131 | MIT, see LICENSE.md
--------------------------------------------------------------------------------
/xml.php:
--------------------------------------------------------------------------------
1 | xml = (
25 | ($data[0] == DIRECTORY_SEPARATOR && file_exists($data))
26 | ?
27 | file_get_contents($data)
28 | :
29 | $data
30 | );
31 | if(!empty($this->xml) && $this->xml[0] == '<')
32 | {
33 | $this->parse();
34 | }
35 | break;
36 |
37 | case 'array':
38 | $this->data = $data;
39 | break;
40 | }
41 | }
42 |
43 | public function __toString()
44 | {
45 | return (
46 | (isset($this->declaration)&&trim($this->declaration))
47 | ?
48 | "{$this->declaration}?>"
49 | :
50 | ''
51 | ) . $this->traverse($this->data);
52 | }
53 |
54 | private function traverse($node)
55 | {
56 | $xml = '';
57 | $attributes = '';
58 | if(count($node) > 1)
59 | {
60 | foreach(array_slice($node, 1) as $key => $value)
61 | {
62 | $attributes .= ' ' . substr($key, 1) . '="' . $value . '"';
63 | }
64 | }
65 | foreach(array_slice($node, 0, 1) as $tag => $data)
66 | {
67 | switch(gettype($data))
68 | {
69 | case 'array':
70 | $xml .= "<{$tag}{$attributes}>";
71 | if($this->is_assoc($data))
72 | {
73 | foreach($data as $child)
74 | {
75 | $xml .= $this->traverse($child);
76 | }
77 | }
78 | else
79 | {
80 | $xml .= $this->traverse($data);
81 | }
82 | $xml .= "{$tag}>";
83 | break;
84 |
85 | case 'NULL':
86 | $xml .= "<{$tag}{$attributes} />";
87 | break;
88 |
89 | default:
90 | $xml .= "<{$tag}{$attributes}>{$data}{$tag}>";
91 | break;
92 | }
93 | }
94 | return $xml;
95 | }
96 |
97 | private function is_assoc($array)
98 | {
99 | return (
100 | count(
101 | array_filter(
102 | array_keys($array),
103 | 'is_string'
104 | )
105 | ) > 0
106 | );
107 | }
108 |
109 | private function parse()
110 | {
111 | $this->xml = str_replace(
112 | "\t",
113 | ' ',
114 | $this->xml
115 | );
116 |
117 | $this->stack[] =& $this->data;
118 |
119 | for(
120 | $length = strlen($this->xml);
121 | $this->index < $length;
122 | $this->index++
123 | )
124 | {
125 | switch($this->xml[$this->index])
126 | {
127 | case '<':
128 | switch($this->xml[$this->index + 1])
129 | {
130 | case '?':
131 | $this->index += 2;
132 | $this->syntax = 'syntax_declaration';
133 | break;
134 |
135 | case '/':
136 | $this->index += 2;
137 | $this->tag_name = '';
138 | $this->syntax = 'syntax_tag_back_start';
139 | break;
140 |
141 | default:
142 | $this->index += 1;
143 | $this->tag_name = $this->tag_value = '';
144 | $this->attributes = [];
145 | $this->syntax = 'syntax_tag_front_start';
146 | break;
147 | }
148 | break;
149 |
150 | case '/':
151 | switch($this->xml[$this->index + 1])
152 | {
153 | case '>':
154 | $this->index += 1;
155 | if($this->syntax == 'syntax_attribute_name')
156 | {
157 | $this->xml = substr($this->xml, $this->index);
158 | $this->index = 0;
159 | $length = strlen($this->xml);
160 | $this->syntax = 'syntax_tag_short';
161 | }
162 | else
163 | {
164 | $this->syntax = 'syntax_tag_back_end';
165 | }
166 | break;
167 | }
168 | break;
169 |
170 | case '>':
171 | switch($this->syntax)
172 | {
173 | case 'syntax_tag_front_start':
174 | case 'syntax_attribute_name':
175 | $this->syntax = 'syntax_tag_front_end';
176 | break;
177 |
178 | default:
179 | $this->xml = substr($this->xml, $this->index);
180 | $this->index = 0;
181 | $length = strlen($this->xml);
182 | $this->syntax = 'syntax_tag_back_end';
183 | break;
184 | }
185 | break;
186 |
187 | case "\n":
188 | $this->line++;
189 | break;
190 | }
191 |
192 | $this->{$this->syntax}();
193 | }
194 |
195 | unset($this->xml);
196 | }
197 |
198 | // ### Iterator: foreach access ###
199 |
200 | public function rewind()
201 | {
202 | reset($this->data);
203 | }
204 |
205 | public function current()
206 | {
207 | return current($this->data);
208 | }
209 |
210 | public function key()
211 | {
212 | return key($this->data);
213 | }
214 |
215 | public function next()
216 | {
217 | return next($this->data);
218 | }
219 |
220 | public function valid()
221 | {
222 | $key = key($this->data);
223 | return ($key !== null && $key !== false);
224 | }
225 |
226 | // ### ArrayAccess: key/value access ###
227 |
228 | public function offsetSet($offset, $value)
229 | {
230 | if(is_null($offset))
231 | {
232 | $this->data[] = $value;
233 | }
234 | else
235 | {
236 | $this->data[$offset] = $value;
237 | }
238 | }
239 |
240 | public function offsetExists($offset)
241 | {
242 | return isset($this->data[$offset]);
243 | }
244 |
245 | public function offsetUnset($offset)
246 | {
247 | unset($this->data[$offset]);
248 | }
249 |
250 | public function offsetGet($offset)
251 | {
252 | return (
253 | isset($this->data[$offset])
254 | ?
255 | $this->data[$offset]
256 | :
257 | null
258 | );
259 | }
260 |
261 | // ### START ### Declaration ###
262 |
263 | public function version()
264 | {
265 | return (
266 | preg_match('#version\="(.*)"#U', $this->declaration, $match)
267 | ?
268 | $match[1]
269 | :
270 | '1.0'
271 | );
272 | }
273 |
274 | public function encoding()
275 | {
276 | return (
277 | preg_match('#encoding\="(.*)"#U', $this->declaration, $match)
278 | ?
279 | $match[1]
280 | :
281 | 'utf-8'
282 | );
283 | }
284 |
285 | private function syntax_declaration()
286 | {
287 | if(
288 | $this->xml[$this->index] == '?'
289 | &&
290 | $this->xml[$this->index + 1] == '>'
291 | )
292 | {
293 | $this->index++;
294 | $this->syntax = 'syntax_tag_value';
295 | }
296 | else
297 | {
298 | $this->declaration .= $this->xml[$this->index];
299 | }
300 | }
301 |
302 | // ### END ### Declaration ###
303 |
304 | private function syntax_error()
305 | {
306 | error_log("Syntax error in XML data. Please check line # {$this->line}.");
307 | }
308 |
309 | private function syntax_tag_front_start()
310 | {
311 | switch($this->xml[$this->index])
312 | {
313 | case ' ':
314 | $this->syntax = 'syntax_attribute_name';
315 | $this->attribute_name = $this->attribute_value = '';
316 | break;
317 |
318 | default:
319 | $this->tag_name .= $this->xml[$this->index];
320 | break;
321 | }
322 | }
323 |
324 | private function syntax_tag_front_end()
325 | {
326 | $node = [];
327 | $node[$this->tag_name] = [];
328 | if(!empty($this->attributes))
329 | {
330 | foreach($this->attributes as $key => $value)
331 | {
332 | $node["@{$key}"] = $value;
333 | }
334 | }
335 |
336 | $current =& $this->stack[count($this->stack) - 1];
337 | if(empty($current))
338 | {
339 | $current = $node;
340 | $this->stack[] =& $current[$this->tag_name];
341 | }
342 | else
343 | {
344 | if($this->is_assoc($current))
345 | {
346 | $current = [$current, $node];
347 | }
348 | else
349 | {
350 | $current[] = $node;
351 | }
352 | $this->stack[] =& $current[count($current) - 1][$this->tag_name];
353 | }
354 |
355 | $this->syntax = 'syntax_tag_value';
356 | }
357 |
358 | private function syntax_tag_short()
359 | {
360 | $this->syntax_tag_front_end();
361 | $this->syntax_tag_back_end();
362 | }
363 |
364 | private function syntax_tag_back_start()
365 | {
366 | $this->tag_name .= $this->xml[$this->index];
367 | }
368 |
369 | private function syntax_tag_back_end()
370 | {
371 | $child =& $this->stack[count($this->stack) - 1];
372 | array_pop($this->stack);
373 |
374 | $last = count($this->stack) - 1;
375 | if(
376 | isset($this->stack[$last][$this->tag_name])
377 | ||
378 | isset(end($this->stack[$last])[$this->tag_name])
379 | )
380 | {
381 | if(empty($child))
382 | {
383 | $child = (
384 | (
385 | ($this->tag_value = trim($this->tag_value))
386 | &&
387 | $this->tag_value != ''
388 | )
389 | ?
390 | $this->tag_value
391 | :
392 | null
393 | );
394 | }
395 | $this->tag_value = '';
396 | $this->syntax = 'syntax_tag_value';
397 | }
398 | else
399 | {
400 | $this->syntax_error();
401 | }
402 | }
403 |
404 | private function syntax_tag_value()
405 | {
406 | $this->tag_value .= $this->xml[$this->index];
407 | }
408 |
409 | private function syntax_attribute_name()
410 | {
411 | switch($this->xml[$this->index])
412 | {
413 | case '=':
414 | case ' ':
415 | break;
416 |
417 | case '"':
418 | $this->syntax = 'syntax_attribute_value';
419 | break;
420 |
421 | default:
422 | $this->attribute_name .= $this->xml[$this->index];
423 | break;
424 | }
425 | }
426 |
427 | private function syntax_attribute_value()
428 | {
429 | switch($this->xml[$this->index])
430 | {
431 | case '"':
432 | $this->syntax = 'syntax_attribute_end';
433 | $this->index--;
434 | break;
435 |
436 | default:
437 | $this->attribute_value .= $this->xml[$this->index];
438 | break;
439 | }
440 | }
441 |
442 | private function syntax_attribute_end()
443 | {
444 | $this->attributes[$this->attribute_name] = $this->attribute_value;
445 | $this->syntax = 'syntax_tag_front_start';
446 | }
447 | }
448 |
--------------------------------------------------------------------------------
/test/1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Great conversations: the pianists
10 |
11 |
12 | Istomin, Eugene
13 |
14 | Host
15 |
16 |
17 |
18 | Bronfman, Yefim
19 |
20 | Interviewee
21 |
22 |
23 |
24 | Ax, Emanuel
25 |
26 | Interviewee
27 |
28 |
29 |
30 | Fleisher, Leon
31 |
32 | Interviewee
33 |
34 |
35 |
36 | Rosen, Charles
37 |
38 | Interviewee
39 |
40 |
41 |
42 | Graffman, Gary
43 |
44 | Interviewee
45 |
46 |
47 |
48 | Rosen, Peter
49 |
50 | Producer
51 |
52 |
53 | moving image
54 |
55 |
56 | New York
57 |
58 | Peter Rosen Productions, Inc.
59 | 2005
60 | monographic
61 |
62 |
63 | videorecording
64 | access
65 | 1 digibeta videotape; duration: 60 min., 20 sec.
66 | reformatted digital
67 |
68 | adult
69 | Eugene Istomin and his fellow pianists Emanuel Ax, Yefim Bronfman, Leon Fleisher, Gary Graffman, and Charles Rosen offer insights into the world of the piano as they discuss performance technique and adventures in recording, make humorous observations about their colleagues, and tell inside jokes about great musical icons. The conversations were filmed in the elegant surroundings of the Members’ Room in the Library of Congress’ Thomas Jefferson Building.
70 | Program is early edited version and contains the title "The green room," which was later changed to "Great conversations."
71 | "Program one."
72 | In opening credits: "From the Library of Congress, Washington, D.C."
73 | Additional credits: For the Music Division of the Library of Congress: Jon Newsom, chief; Jan Lauridsen, Assist. Chief, Ruth Foss, Program specialist.
74 | Library of Congress extended version.
75 | Copyright Library of Congress. This program was made possible through the courtesy of Eugene Istomin. Artists' appearances are courtesy of themselves: Emanuel Ax, Yefim Bronfman, Leon Fleisher, Gary Graffman, and Charles Rosen.
76 | Copyright Library of Congress. This program was made possible through the courtesy of Eugene Istomin. Artists' appearances are courtesy of themselves: Emanuel Ax, Yefim Bronfman, Leon Fleisher, Gary Graffman, and Charles Rosen.
77 |
78 |
79 | Opening credits; and The early years
80 |
81 | moving image
82 |
83 |
84 | New York
85 |
86 | Peter Rosen Productions, Inc.
87 | 2005
88 |
89 |
90 | video
91 | access
92 | 11:53
93 | reformatted digital
94 |
95 | Istomin introduces his guests and initiates a conversation on the influences that made each become a pianist. Rosen and Graffman share anecdotes about playing for Leopold Godowsky.
96 |
97 |
98 |
99 | Roots
100 |
101 | moving image
102 |
103 |
104 | New York
105 |
106 | Peter Rosen Productions, Inc.
107 | 2005
108 |
109 |
110 | video
111 | access
112 | 7:33
113 | reformatted digital
114 |
115 | Istomin and his guests talk about the roots of various piano traditions and national schools of piano technique.
116 |
117 |
118 |
119 | Performance
120 |
121 | moving image
122 |
123 |
124 | New York
125 |
126 | Peter Rosen Productions, Inc.
127 | 2005
128 |
129 |
130 | video
131 | access
132 | 9:55
133 | reformatted digital
134 |
135 | Istomin and his guests share opinions on twentieth-century pianists who returned to the Urtext as a basis for interpretation as well views on those who exercise an excess of bodily motion in performance.
136 |
137 |
138 |
139 | Tradition
140 |
141 | moving image
142 |
143 |
144 | New York
145 |
146 | Peter Rosen Productions, Inc.
147 | 2005
148 |
149 |
150 | video
151 | access
152 | 8:34
153 | reformatted digital
154 |
155 | Istomin reminisces about the origins of the first recording Sergei Rachmaninoff’s Piano Concerto No. 4 in D minor, Op. 40. Fleischer and Graffman talk about pedagogy.
156 |
157 |
158 |
159 | Interpretation
160 |
161 | moving image
162 |
163 |
164 | New York
165 |
166 | Peter Rosen Productions, Inc.
167 | 2005
168 |
169 |
170 | video
171 | access
172 | 7:58
173 | reformatted digital
174 |
175 | Istomin and his guests discuss what it means to interpret a piece of music.
176 |
177 |
178 |
179 | Tone
180 |
181 | moving image
182 |
183 |
184 | New York
185 |
186 | Peter Rosen Productions, Inc.
187 | 2005
188 |
189 |
190 | video
191 | access
192 | 11:25
193 | reformatted digital
194 |
195 | Istomin plays a portion of Rachmaninoff’s Piano Concerto No. 4, which leads to a discussion of tone.
196 |
197 |
198 |
199 | Epilogue; and Closing credits
200 |
201 | moving image
202 |
203 |
204 | New York
205 |
206 | Peter Rosen Productions, Inc.
207 | 2005
208 |
209 |
210 | video
211 | access
212 | 3:02
213 | reformatted digital
214 |
215 | Istomin provides an epilogue to the discussions by paying homage to other great pianists, including Ignace Paderweski, Artur Schnabel, Rudolf Serkin, Claudio Arrau, and Dame Myra Hess.
216 |
217 | 200031106
218 | 23601
219 |
220 | Music Division
221 | DLC
222 |
223 |
224 | IHAS
225 | 051125
226 | loc.natlib.ihas.200031106
227 |
228 | greatconv
229 | Great Conversations in Music
230 |
231 |
232 | Great Conversations in Music
233 |
234 |
235 | http://lcweb2.loc.gov/diglib/ihas/html/greatconversations/great-home.html
236 |
237 |
238 |
239 |
240 | Performing Arts Encyclopedia
241 |
242 |
243 | http://www.loc.gov/performingarts
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
--------------------------------------------------------------------------------