Using XMLUtil
❘
279
The
XMLUtil.Walk()
function is so important because it demonstrates a Python generator
(described later in the section when you have the required background). Most languages don’t pro-
vide support for generators, so they require a little explanation. The issue at the center of this whole
discussion is the variant list. You know that an application will need to process some number of
items during run time, but you have no idea of how long this list is or whether the list will exist at
all. A producer function is one that outputs values one at a time in response to a request. The pro-
ducer keeps processing items until it runs out, so the length of the list is no longer a concern (even if
the list contains no items at all). Most languages rely on a callback, an address to the requestor, to
provide a place to send the producer output. The problem with using a callback is that the code must
provide some means of retaining state information to remember previous values. In some cases,
using callbacks leads to unnatural, convoluted coding techniques that are hard to write, harder to
understand, and nearly impossible to update later.
Developers have a number of alternatives they can use. For example, the developer could simply use
a very large
list
. However,
list
s require that the developer know what values should appear in the
list
during design time, and lists can consume large quantities of memory, making them a less than
helpful solution in many cases. Another solution is to use an
iterator
to perform the task. Using
an
iterator
makes it easier to get out of a loop when the processing is finished and eliminates the
memory requirements. However, using an
iterator
shifts the burden of maintaining state informa-
tion to the producer, complicating an already difficult programming task because the producer may
not know anything about the caller. There are other solutions, as well, such as running the requestor
and producer on separate threads so that each object can maintain state information without worrying
about the potential corruption that occurs when running the code on a single thread. Unfortunately,
multithreaded applications can run slowly and require a platform that fully supports multithreading,
making your application less portable. In short, most languages don’t provide a good solution to the
problem of working with data of variant length.
A generator creates a situation where the producer continuously outputs individual results as
in a loop, maintaining its state locally. The requestor actually views the function as a type of
iterator
, even though the producer isn’t coded to provide an
iterator
. To accomplish this
task, Python provides the
yield
statement shown in Figure 13-5. The
yield
statement returns
an intermediate result from the producer to the requestor, while the producer continues to pro-
cess a list of items.
The code in Figure 13-5 begins with the definition of a function named
Walk()
. This function accepts
some kind of XML as input. The first
yield
statement sends the entire
xml
input back to the requestor
(the example application shown in Listing 13-2). Consequently, you see
#document
as the
Name
and the
entire XML document as the
InnerXml
.
The second call to
Walk()
moves past the first
yield
statement. Because the second item doesn’t
meet the
hasattr(xml, “Attributes“)
requirement, the code moves onto the loop statement at
the bottom of the code listing shown in Figure 13-5. The effect of this loop is to obtain the child
elements of the entire document. So the second call to
Walk()
ends with
yield c
, which returns
the XML declaration element. As a result, you see
xml
for the
Name
,
version=“1.0“
encoding=“utf-8“ standalone=“yes“
for the
Value
, and nothing for the
InnerXml
.
This second call ends processing of the XML declaration.
548592c13.indd 279
2/24/10 12:48:58 PM
www.finebook.ir
Do'stlaringiz bilan baham: |