Introduction to XML in Flash
by senocular
Example: News Editor
This example takes XML data editing to the next
level. It does not simply display and let you
change one text node. This example will let
you add, edit and delete up to five entries
each of which consist of two editable text fields
(nodes). Together they create a small and simple
news feed application. Take a gander:
[
show, add, edit, and/or delete news items ]
Initially you see the news display where all
news is loaded and formatted for viewing. Using
the refresh button, you can reload the content
reflecting any changes that might have occurred
since it was initially loaded when the movie
began. The edit button brings you to the edit
screen.
The edit screen, which lies on a different
frame, allows you to edit the XML. It provides
arrows for navigating the entries currently
loaded within the player from the initial news
view and provides text fields for changing their
values. The first entry is labeled as [ New
] and is not an entry at all but a way to create
new entries. This was to keep the file as simple
as possible while still maintaining a good deal
of functionality. Likewise, there is no delete
button but you can delete entries by clearing
their text fields and saving.
Whenever you save from the edit screen, the
XML will be edited, sent to the server and the
result will be reloaded and displayed back in
the original news view.
The XML
Since basically all nodes within the XML are
dynamically created, the base XML file simply
consists of one node:
- <news />
(If you're too lazy to create
your own, you can get this
here.)
Every entry within the news element is created
from within the Flash movie. The structure of
a complete entry is as follows:
- <entry date="Thu
Aug 26 10:35:20 GMT-0400 2004">
- <title>title
text</title>
- <body>body
text</body>
- </entry>
Where up to five may exist within the news
element at any given time (this is a limit created
within the code that can be altered if desired).
The text within the title and body elements
are both editable whereas the date attribute
value is defined automatically.
ActionScript
Since this example is far more complex than
some of the others, I'm only going to cover
the important parts and let you work your through
the source file to figure out all of the other
details. Those important parts are creating
new entries and editing existing ones. The methods
involved in doing that are AddNewsEntry and
EditNewsEntry.
AddNewsEntry generates a a new, full entry
node assigning title and body to respective
values passed into the function call.
- AddNewsEntry
= function(news_xml,
title, body){
- var entryNode
= news_xml.createElement("entry");
- entryNode.attributes.date
= new
Date().toString();
-
- var titleNode
= news_xml.createElement("title");
- var titleText
= news_xml.createTextNode(title);
- titleNode.appendChild(titleText);
- entryNode.appendChild(titleNode);
-
- if (body
== "")
body =
"(none)";
- var bodyNode
= news_xml.createElement("body");
- var bodyText
= news_xml.createTextNode(body);
- bodyNode.appendChild(bodyText);
- entryNode.appendChild(bodyNode);
-
- if (news_xml.firstChild.hasChildNodes()){
- news_xml.firstChild.insertBefore(entryNode,
news_xml.firstChild.firstChild);
- }else
news_xml.firstChild.appendChild(entryNode);
-
- while (GetNewsCount(news_xml)
> max_news_items){
- news_xml.firstChild.lastChild.removeNode();
- }
- }
You can see that AddNewsEntry starts off creating
an entry element ("free floating")
using createElement. Added to its attributes
object is a variable called date which is assigned
to be the current data (as determined by Flash
using the Date object).
- var entryNode
= news_xml.createElement("entry");
- entryNode.attributes.date
= new
Date().toString();
Next the title element is created.
- if (title
== "")
title =
"(none)";
- var titleNode
= news_xml.createElement("title");
- var titleText
= news_xml.createTextNode(title);
- titleNode.appendChild(titleText);
- entryNode.appendChild(titleNode);
The title element also contains a text node
child element that contains the text for the
title of the entry. This text is passed in to
AddNewsEntry as the variable title and is used
in creating a text node called titleText (assuming
its not empty, in which case "(none)"
is used to describe its contents). After both
nodes are created (the title element and the
text node to contain the title text), which
are both homeless at the time of creation, they
are placed in their respective final locations
with appendChild; the text node within the title
element and the title element within the entry
node created earlier.
The body element is created next in the same
manner as title.
- if (body
== "")
body =
"(none)";
- var bodyNode
= news_xml.createElement("body");
- var bodyText
= news_xml.createTextNode(body);
- bodyNode.appendChild(bodyText);
- entryNode.appendChild(bodyNode);
This gives the entry node two children, title
and body, both of whom have a single text node
to contain the title and body text. The entry
node itself, however, is still without a home.
Giving it one is just a matter of putting it
in the main news node of the XML.
Before doing that, however, think about how
XML is typically read and how these news entries
are to be ordered. Typically, XML is read from
top to bottom, where you look at the first element
of a set of child nodes and work your way through
to the bottom. When the news is accessed, displayed
and read, you would want the newest news to
be at the top with older news below it. Since
AddNewsEntry creates new news, this means that
the new entry being created should be inserted
at the top of the list of all the other news.
Of course, if there are no news entries, it
would just be added normally. That's what the
next section of code does.
- if (news_xml.firstChild.hasChildNodes()){
- news_xml.firstChild.insertBefore(entryNode,
news_xml.firstChild.firstChild);
- }else
news_xml.firstChild.appendChild(entryNode);
This checks to see whether or not the news
element (news_xml.firstChild) has any child
nodes. If so, insertBefore is used to put the
new entry at the top of the list within those
nodes. Otherwise, appendChild is used to simply
add it.
That brings us to the end of the function where
one final action takes place to make sure that
the news entries don't go beyond the specified
maximum number of entries.
- while (GetNewsCount(news_xml)
> max_news_items){
- news_xml.firstChild.lastChild.removeNode();
- }
Where GetNewsCount is a custom function used
to count the number of news items or entries
within the news element of the passed XML.
The EditNewsEntry function works a little differently,
obviously. After all, its editing news, not
adding it. Here's what it looks like:
- EditNewsEntry
= function(news_xml,
node_index, title,
body){
- var entry
= GetEntry(news_xml,
node_index);
- if (title
== ""
&& body
== ""){
- entry.removeNode();
- return
(0);
- }else{
- if (title
== "")
title =
"(none)";
- if (body
== "")
body =
"(none)";
- }
- entry.attributes.date
= new
Date().toString();
- var titleTextNode
= entry.firstChild.firstChild;
- var bodyTextNode
= entry.firstChild.nextSibling.firstChild;
- titleTextNode.nodeValue
= title;
- bodyTextNode.nodeValue
= body;
- }
Since this function can edit any one of the
multiple news entries, in addition to the arguments
received by AddNewsEntry, EditNewsEntry also
gets a node_index argument that specifies which
node exactly is to be edited. The reference
to that particular node is then obtained using
the custom function GetEntry.
- var entry
= GetEntry(news_xml,
node_index);
Next some checks are made for both the title
and news arguments. If both are empty, the entry
is removed and the function is exited using
return - this being the little added delete
feature (which could have just as well been
used separately). Otherwise if any one of them
is empty, "(none)" is used to represent
their contents.
- if (title
== ""
&& body
== ""){
- entry.removeNode();
- return (0);
- }else{
- if (title
== "")
title =
"(none)";
- if (body
== "")
body =
"(none)";
- }
All that remains is the simple re-assignment
of text values. As with many other cases, variables
are used to help show where this is happening.
- entry.attributes.date
= new
Date().toString();
- var titleTextNode
= entry.firstChild.firstChild;
- var bodyTextNode
= entry.firstChild.nextSibling.firstChild;
- titleTextNode.nodeValue
= title;
- bodyTextNode.nodeValue
= body;
Once a new entry is added with AddNewsEntry
or an existing one edited or deleted with EditNewsEntry,
The XML can then be saved to the server. This
is accomplished using the SaveNews function.
- SaveNews =
function(news_xml){
- content_txt.htmlText
= "<i>Saving
and Loading...</i>";
- news_xml.xmlDecl
= "";
// fixes duplication
bug
- news_xml.sendAndLoad(save_script,
news_xml);
- }
Using sendAndLoad the new version is sent to
the server to be saved and the result which
is simply the new XML is sent back to the news_xml
instance whose onLoad displays the entries in
the XML received.
- news_xml.onLoad
= function(success){
- if (success)
ShowNews(this);
- else content_txt.text
= "Error
loading XML file";
- }
That combined with the other details of the
file give you a working news editor! Granted,
these aren't RSS feeds we're dealing with here,
but the simple format of the XML used here still
gets the job done (and an RSS feed would actually
not be too terribly far off from this).
Note: If you look at the ShowNews function in the source file, you'll notice that the title and news body is set to the text field's htmlText.
- content_txt.htmlText += "<b>" + title +"</b><br>"
- content_txt.htmlText += entries[i].attributes.date + "<br>"
- content_txt.htmlText += "ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ<br>"
- content_txt.htmlText += body +"<br><br>";
This means that when you make or edit a news entry, you would need to use text that is valid HTML (i.e. using character entity references where needed.
This does NOT mean that the XML contains invalid characters. The XML correctly replaces those characters as needed when stored. However, when they
reloaded and placed in the textfield, they are restored to their respective characters. For example, < becomes <. This can be desirable or not. If you
don't want this behavior, use the text nodes toString() value as opposed to their nodeValue to be placed within the htmlText of the text field.
|