Importing, Exporting, and Manipulating XML in Mathematica

Draft 10/8/2001

Chris Hill
Wolfram Research
chill@wolfram.com

Abstract

XML is a structured data representation language with strong support from every corner of the computing world.  Mathematica will soon support an expression format for representing XML data.  This talk will include an overview of the XML representation and the XML Import and Export process.  Examples utilizing Mathematica's symbolic manipulation facilities to extract and transform XML data will be presented.

SymbolicXML

What is SymbolicXML?

SymbolicXML is used to represent XML data as a Mathematica expression.  It can be used to hold any XML data.  XML is a syntax for tree structured data with attributes, this is what SymbolicXML represents.  

The semantics of the structured data is not part of the XML syntax, but is part of a particular XML format.

Why use SymbolicXML?

Mathematica has always had strong support for structured data manipulation, and with XML there is now a standard way to exchange structured data and documents with the world.

Importing

Use Mathematica to process and visualize your data and documents.  Mathematica provides the tools to turn your XML files and strings into a Mathematica expression.

Exporting

Share the results of Mathematica computations with all languages and systems which support XML.  Convert Notebooks to custom XML document formats.

Manipulating

Use the standard Mathematica expression processing features such as patterns and replacement rules to transform XML data.  The Mathematica language is well equipped to deal with symbolic expression.

As Development Platform

SymbolicXML is the foundation upon which you can build support for custom or industry standard XML data formats.  Within Mathematica, SymbolicXML is the preferred way to exchange XML data.

How does SymbolicXML relate to the other XML features in Mathematica?

Specific XML formats

Mathematica understands the semantics of MathML and NotebookML.  Support for both of these technologies is implemented on top of SymbolicXML.  In the future, support for more XML data formats will be provided.

J/Link

J/Link enables Mathematica to use the XML processing functionality that is available in Java such as the DOM and SAX APIs.  J/Link can be used to produce SymbolicXML.

XML and SymbolicXML side-by-side

Here are some XML fragments with corresponding SymbolicXML fragments

<tagname>Contents</tagname>

XMLElement["tagname", {}, {"Contents"}]

<tagname attribute="value">Contents</tagname>

\(XMLElement["tagname", {"attribute" -> "value"}, {"Contents"}]\)

<tagname attribute="value">Contents<anothertag/></tagname>

\(XMLElement["tagname", {"attribute" -> "value"}, {"Contents", XMLElement["anothertag", {}, {}]}]\)

<tagname attribute='value' secondattribute='secondvalue'>Contents</tagname>

\(XMLElement["tagname", {"attribute" -> "value", "secondattribute" -> "secondvalue"}, {"Contents"}]\)

SymbolicXML expression format

There are only two symbols in the SymbolicXML format, XMLElement and XMLObject.  Element names, attribute names and values are placed in strings to prevent new or conflicting symbols from being defined as XML data is imported.

Tree structure

XMLElement["tagname", {attributes}, {contents}]

Attributes is a sequence of rules of the form

"name" -> "value"

contents is a sequence of strings (for character data) and XMLElement objects (for nested elements)

Document wrapper

The document wrapper contains information located outside of the root element of the document such as: XML version, DOCTYPE, Comments and Processing Instructions outside the root element

The most interesting part of an XML document is of course the tree itself, which is always available as the second part of the document.

XMLObject["Document"][{prolog}, {document tree}, {epilog}]

ImportString["<?xml version='1.0'?><root/>", "XML"]

Additional XML objects

There are several additional XML objects that represent data other than the document tree.  When importing, by default no XMLObjects are included within the document tree itself to ease processing.

XMLObject["Doctype"]["name", "Public" -> "", "\
System" -> ""]

\(\(XMLObject["Declaration"]\)["Version" -> "1.0", "Encoding" -> "UTF-8", "Standalone" -> "yes"]\)

\(\(XMLObject["ProcessingInstruction"]\)["target", "value"]\)

XMLObject["Comment"]["comment text"]

Importing XML data

Importing XML data is done using the standard Import or ImportString functions.  The exact behavior can be modified by specifying a format and conversion options.  Importing converts the XML from a byte stream to a SymbolicXML expression, so you can concentrate on the structure of the XML data, not the finer details of XML encoding.

Examples

Simple Examples

Import["xhtml.xml"]

\(ImportString["<!--This is a simple document--><xmldata/>", "XML"]\)

Import can handle standard XML encodings like UTF8 and UTF16.  The characters are returned in Unicode form.

Import["japan.xml"]

Numeric character references are automatically resolved

ImportString["<hand>
<card suit='&#9824;' value='2'/>
<card suit='&#9825;' value='10'/>
<card suit='&#9826;' value='6'/>
<card suit='&#9827;' value='4'/>
<card suit='&#9827;' value='5'/>
</hand>", "XML"]

Named character entities are resolved from the DTD or internal subset

ImportString["<!DOCTYPE root [<!ENTITY myentity 'beer'>]>
<root>
  &myentity;
</root>", "XML",  
      ConversionOptions -> {"ValidateAgainstDTD" -> 
            False}]

Importing MathML in several ways

ImportString["<math><mrow><mfrac><mi>q</mi><msqrt><mn>2</mn></msqrt></\
mfrac></mrow></math>", "MathML"] // DisplayForm

Using ConversionOptions to control Namespace processing

Import["mathml.xml", "SymbolicXML"]

Import["mathml.xml", "SymbolicXML", 
      ConversionOptions -> {"IncludeNamespaces" -> 
            True}]

Including the full namespace information is most useful in documents with mixed namespaces, such as XHTML with embedded MathML.

Import["xhtml.xml", "SymbolicXML", 
      ConversionOptions -> {"IncludeNamespaces" -> 
            True}]

Validating XML data against a DTD

In addition to simply converting an XML data to a SymbolicXML expression, Import can validate the XML data to ensure that it conforms to a content model defined by a DTD.

So long as the document is well formed, a SymbolicXML expression will be returned.  If the document is not valid warning messages will be issued and the document wrapper will indicate the invalid nature of the document with the option Valid->False.

Invalid NotebookML

ImportString["<!DOCTYPE Notebook SYSTEM \
'http://www.wolfram.com/XML/NotebookML/NotebookML.dtd'><Notebook></Notebook>\
", "XML"]

Symbolic XML import formats

XML

Automatic detection of Mathematica supported XML formats such as MathML and NotebookML.  A NotebookML document would be imported as a Notebook expression.  If the XML is not of a recognized type, it will be returned in SymbolicXML form.

SymbolicXML

Represents generic XML data.  This format can be used with Import to specify that even recognized data such as MathML should be returned in SymbolicXML format.

ConversionOptions for SymbolicXML

The standard ConversionOptions feature of the Import system can be used for greater control over the import process.

Whitespace Handling

"NormalizeWhitespace"

DTD processing

"ReadDTD"

"ValidateAgainstDTD"

"AllowRemoteDTDAccess"

"AllowUnrecognizedEntities"

Filtering unwanted XML constructs

"IncludeNamespaces"

"IncludeEmbeddedObjects"

Exporting XML data

As you might expect, exporting to XML is simply a matter of passing SymbolicXML data to the Export function.

Examples

SymbolicXML

data = Import["xhtml.xml"]

Export["xhtml2.xml", data, "XML"];

From a Mathematica expression

s = Soldier["Name", "Rank", "Serial No"];

a = Army[s]

xmlarmy = 
      a //. {Soldier[name_, rank_, serialnum_] -> 
            XMLElement["soldier", {"name" -> 
                  name, "rank" -> rank, "serial" -> 
                  serialnum}, {}], 
          Army[members_] -> 
            XMLElement["army", {}, {members}]}

ExportString[xmlarmy, "XML"]

MathML

Export["integral.xml", (∫_a^b)(Sqrt[ x + 
                  1]) \[DifferentialD]x, "MathML"];

NotebookML

Export["BasicInputPalette.xml", 
        First[Notebooks["BasicInput"]], "NotebookML"];

ConversionOptions

The standard ConversionOptions feature of the Export system can be used for greater control over the import process.

ElementFormatting

Used to control indentation

ExportString[
      ImportString["<root><child/><child/><child/></root>", "XML"], "\
XML", 
      ConversionOptions -> {"ElementFormatting" -> 
            None}]

EntityNameSet

Manipulating XML data

Mathematica supports each stage of XML data processing: Import, Manipulation, Export.  To solve a particular problem you may not use every stage.  Mathematica is uniquely suited to process symbolic expressions with it's powerful pattern matching capabilities.

SymbolicXML->SymbolicXML

Filtering Data using replacement rules

data = 
      ImportString["<data><normal/><normal/><classified/><classified/><\
normal/></data>", "XML"]

ExportString[data, "XML"]

RemoveClassifiedData[xml_] := 
        xml /. XMLElement["classified", __] -> 
            Sequence[];

declassified = RemoveClassifiedData[data]

ExportString[declassified, "XML"]

Displaying SymbolicXML

Use ExportString to view SymbolicXML

data = XMLObject["Document"][{}, 
          XMLElement["root", {}, {XMLElement["child", {}, {}], 
              XMLElement["child", {}, {}], 
              XMLElement["child", {}, {}]}], {}];

ExportString[data, "XML"]

Converting a XML file to a Notebook for viewing

NotebookPut@MakeXMLNotebook@
          ImportString[
            ExportString[
              (1/(Sqrt[2])), "MathML"], "SymbolicXML"];

Implementation

XMLNote[s_String, m_Integer] := 
        Cell[s, Background -> GrayLevel[0.9], 
          CellMargins -> {{m + 25, Inherited}, {Inherited, 
                Inherited}}];

XMLNote[{an_, a_} -> v_, m_Integer] := 
      Cell[TextData[StyleBox[an, FontColor -> Hue[0.6]], " ", 
          StyleBox[a, FontWeight -> "Bold"], " = ",  
          StyleBox[v, Background -> GrayLevel[0.8]]], 
        CellMargins -> {{m + 5, Inherited}, {Inherited, 
              Inherited}}]

XMLNote[a_String -> v_, m_Integer] := 
      Cell[TextData[
          StyleBox[a, FontWeight -> "Bold"], " = ",   StyleBox[v, 
            Background -> GrayLevel[0.8]]], 
        CellMargins -> {{m + 5, Inherited}, {Inherited, 
              Inherited}}]

XMLNote[x_XMLElement, m_Integer] := 
      Cell[CellGroupData[{Cell[
              TextData[
                StyleBox[First[x], FontFamily -> "Swiss", 
                  FontWeight -> "Bold", FontSize -> 15]]], 
            Sequence @@ (XMLNote[#, m] &) /@ x[[2]], 
            Sequence @@ (XMLNote[#, m + 30] &) /@ x[[3]]}, 
          Closed], 
        CellMargins -> {{m, Inherited}, {Inherited, 
              Inherited}}]

MakeXMLNotebook[d_] := 
        Notebook[{XMLNote[d[[2]], 0]}, 
          CellGrouping -> "Manual"];

Using MakeBoxes for syntax coloring

Unprotect[XMLElement]; 
    MakeBoxes[XMLElement[element_String, rest__], StandardForm] ^:= 
      RowBox[{StyleBox[MakeBoxes[element], FontWeight -> "Bold", 
            FontFamily -> "Swiss", FontColor -> Hue[0.6]], "[", 
          Sequence @@ MakeBoxes /@ {rest}, "]"}];

\(ImportString["<root><child attribute='value' second='value2'/><child/><child><grandchild/></child></root>", "XML"]\)

XMLElement /: MakeBoxes[XMLElement[element_String, rest__], 
          StandardForm] =.

Basic Strategies for working with SymbolicXML

SymbolicXML is designed to be easy to use with pattern matching, so a familiarity with pattern syntax is essential when manipulating SymbolicXML.

Extracting Data

Use the Cases function to extract snippets of the SymbolicXML expression, optionally transforming them at the same time.

AL = Import["ALHitters.xml"];

players = 
        Cases[AL, XMLElement["PlayerRecord", ___], 
          Infinity];

Length[players]

yankees = 
        Cases[AL, 
          XMLElement["PlayerRecord", _, {___, 
              XMLElement["TEAM", _, {"NYY"}], ___}], 
          Infinity];

Length[yankees]

GetName[playerrecord_] := 
        First[Cases[playerrecord, 
            XMLElement["PLAYER", _, {name_}] -> name, 
            2]];

Map[GetName, yankees]

Complete transformation

For each element and attribute, transform it to the desired expression.

NL = Import["NLPitchers.xml"];

myTransform[XMLElement[_, _, children_]] := 
        Apply[Sequence, Map[myTransform, children]];

myTransform[s_String] := s;

myTransform[XMLObject["Document"][_, 
            root_, _]] := {myTransform[root]};

myTransform[PlayerAttribute[XMLElement[name_, _, {value_}]]] := 
        name -> value;

myTransform[XMLElement["PlayerRecord", _, children_]] := 
        Pitcher @@ 
          Map[myTransform[PlayerAttribute[#]] &, children];

First[myTransform[NL]]

Modifying Data

Use replacement rules to change portions of the SymbolicXML expression, returning a modified version of the input.

XML data->SymbolicXML->format specific representation

Converting Molecule Descriptions to 3D Graphics

ModL describes molecules http://violet.csa.iisc.ernet.in/~modl/

methane = Import["methane.xml"]

Show[ModLToGraphics3D[methane]];

Implementation

<< Graphics`Shapes`

ModLToGraphics3D[modl_] := 
      Block[{defs = 
            Cases[modl, XMLElement["DEFINE", __], 
              Infinity], 
body = 
            First[Cases[modl, XMLElement["body", __], 
                Infinity]], 
gr, moldef, themols, 
          theatoms}, 
ProcessDefinition /@ 
          defs; 
themols = 
          Flatten@Cases[body, 
              XMLElement["molecule", {"type" -> 
                      t_, ___}, __] :> moldef[t], 
              Infinity]; 
theatoms = 
          Cases[body, 
            XMLElement["atom", {___, "type" -> 
                    t_, "position" -> p_, ___}, __] :> 
              Append[moldef[t], MolPosToList[p]], 
            Infinity]; 
Graphics3D[
          MolToGraphics /@ Join[themols, theatoms], 
          Boxed -> False]
]

ProcessDefinition[
          XMLElement["DEFINE", {"name" -> 
                name_String}, {XMLElement["molecule", {}, 
                subdef___]}]] := (moldef[name] = 
            ProcessSubdef /@ subdef);

\(\(ProcessDefinition[
          XMLElement["DEFINE", {"name" -> 
                name_String}, {XMLElement["atom", {a__}, {}]}]] := \((moldef[name] = Atom[GetRad[a], GetColor[a]])\);\)\)

ProcessSubdef[
          XMLElement["atom", {"type" -> t_, "id" -> 
                id_, pos___}, {}]] := (moldef[id] = 
            Append[moldef[t], GetPos[pos]]);

ProcessSubdef[
        XMLElement["bond", {"atom1" -> a1_, "atom2" -> 
              a2_}, {}]] := 
      Bond[moldef[a1][[3]], moldef[a2][[3]]]

MolStringListToList[molstringlist_String] := 
        Module[{stream = StringToStream[molstringlist], thelist}, 
          thelist = Read[stream, {Number, Number, Number}]; Close[stream]; 
          thelist];

MolColorToRGBColor[molcolor_String] := 
        RGBColor @@ MolStringListToList[molcolor];

MolPosToList[molpos_String] := 
        MolStringListToList[molpos];

GetPos[___, "position" -> p_, ___] := 
        MolPosToList[p];

GetRad[___, "radius" -> r_, ___] := 
        ToExpression[r];

GetColor[___, "color" -> c_, ___] := 
        MolColorToRGBColor[c];

GetColor[___] := GrayLevel[1];

MolToGraphics[Bond[pts__]] := {Thickness[0.01], Line[{pts}]}

MolToGraphics[Atom[r_, col_, pos_]] := {SurfaceColor[col], 
          EdgeForm[], TranslateShape[Sphere[r, 10, 10], pos]};

format specific representation->SymbolicXML->XML data

Converting Notebooks to BioML

Verifying SymbolicXML syntax

SymbolicXMLErrors[
      XMLElement[ele, {att -> val}, {Sin[x]}]]

Part specification

\(\(data = \(XMLObject["Document"]\)[{}, 
          XMLElement["NationalLeagueIndividualPitchers", {}, {XMLElement["PlayerRecord", {}, {XMLElement["PLAYER", {}, {"Randy Johnson"}], XMLElement["TEAM", {}, {"ARI"}], 
                  XMLElement["POS", {}, {"SP"}], 
                  XMLElement["GP", {}, {"35"}], 
                  XMLElement["GS", {}, {"35"}], 
                  XMLElement["STATUS", {}, {"A"}], 
                  XMLElement["W", {}, {"19"}], 
                  XMLElement["L", {}, {"7"}], 
                  XMLElement["S", {}, {"0"}], 
                  XMLElement["IP", {}, {"248.2"}], 
                  XMLElement[ERA, {}, {"2.64"}], 
                  XMLElement["ParkAdj", {}, {"0.97441"}], 
                  XMLElement["PAERA", {}, {"2.57"}], 
                  XMLElement["_90ERA", {}, {"5.94"}], 
                  XMLElement["_50ERA", {}, {"4.54"}], 
                  XMLElement["RPper9inn", {}, {"3.4"}], 
                  XMLElement["RP", {}, {"93.0"}], 
                  XMLElement["RunRatio", {}, {"0.64"}], 
                  XMLElement["PAERAWinsOver162", {}, {"123.461"}], 
                  XMLElement["Games", {}, {"27.6"}], 
                  XMLElement["PAERAwins", {}, {"21.0"}], 
                  XMLElement["PAERAloses", {}, {"6.6"}], 
                  XMLElement["AVG", {}, {"0.213"}], 
                  XMLElement["OBA", {}, {"0.276"}], 
                  XMLElement["ShutOut", {}, {"3"}], 
                  XMLElement["H", {}, {"202"}], 
                  XMLElement["R", {}, {"89"}], 
                  XMLElement["ER", {}, {"73"}], 
                  XMLElement["HR", {}, {"23"}], 
                  XMLElement["K", {}, {"347"}], 
                  XMLElement["WP", {}, {"5"}], 
                  XMLElement["BLK", {}, {"2"}], 
                  XMLElement["HBP", {}, {"6"}], 
                  XMLElement["E", {}, {"3"}], 
                  XMLElement["Salary", {}, {"13350000"}], 
                  XMLElement["DollarsPerRun", {}, {"143563"}], 
                  XMLElement["PictureIndex", {}, {"7762"}]}], 
              XMLElement["PlayerRecord", {}, {XMLElement["PLAYER", {}, {"Greg Maddux"}], XMLElement["TEAM", {}, {"ATL"}], 
                  XMLElement["POS", {}, {"SP"}], 
                  XMLElement["GP", {}, {"35"}], 
                  XMLElement["GS", {}, {"35"}], 
                  XMLElement["STATUS", {}, {"A"}], 
                  XMLElement["W", {}, {"19"}], 
                  XMLElement["L", {}, {"9"}], 
                  XMLElement["S", {}, {"0"}], 
                  XMLElement["IP", {}, {"249.1"}], 
                  XMLElement["ERA", {}, {"3.00"}], 
                  XMLElement["ParkAdj", {}, {"0.98749"}], 
                  XMLElement["PAERA", {}, {"2.96"}], 
                  XMLElement["_90ERA", {}, {"5.94"}], 
                  XMLElement["_50ERA", {}, {"4.54"}], 
                  XMLElement["RPper9inn", {}, {"3.0"}], 
                  XMLElement["RP", {}, {"82.5"}], 
                  XMLElement["RunRatio", {}, {"0.60"}], 
                  XMLElement["PAERAWinsOver162", {}, {"113.138"}], 
                  XMLElement["Games", {}, {"27.7"}], 
                  XMLElement["PAERAwins", {}, {"19.3"}], 
                  XMLElement["PAERAloses", {}, {"8.3"}], 
                  XMLElement["AVG", {}, {"0.231"}], 
                  XMLElement["OBA", {}, {"0.270"}], 
                  XMLElement["ShutOut", {}, {"3"}], 
                  XMLElement["H", {}, {"225"}], 
                  XMLElement["R", {}, {"91"}], 
                  XMLElement["ER", {}, {"83"}], 
                  XMLElement["HR", {}, {"19"}], 
                  XMLElement["K", {}, {"190"}], 
                  XMLElement["WP", {}, {"1"}], 
                  XMLElement["BLK", {}, {"2"}], 
                  XMLElement["HBP", {}, {"10"}], 
                  XMLElement["E", {}, {"2"}], 
                  XMLElement["Salary", {}, {"11100000"}], 
                  XMLElement["DollarsPerRun", {}, {"134493"}], 
                  XMLElement["PictureIndex", {}, {"7837"}]}], 
              XMLElement["PlayerRecord", {}, {XMLElement["PLAYER", {}, {"Kevin Brown"}], XMLElement["TEAM", {}, {"LOS"}], 
                  XMLElement["POS", {}, {"SP"}], 
                  XMLElement["GP", {}, {"33"}], 
                  XMLElement["GS", {}, {"33"}], 
                  XMLElement["STATUS", {}, {"A"}], 
                  XMLElement["W", {}, {"13"}], 
                  XMLElement["L", {}, {"6"}], 
                  XMLElement["S", {}, {"0"}], 
                  XMLElement["IP", {}, {"230.0"}], 
                  XMLElement["ERA", {}, {"2.58"}], 
                  XMLElement["ParkAdj", {}, {"1.06913"}], 
                  XMLElement["PAERA", {}, {"2.76"}], 
                  XMLElement["_90ERA", {}, {"5.94"}], 
                  XMLElement["_50ERA", {}, {"4.54"}], 
                  XMLElement["RPper9inn", {}, {"3.2"}], 
                  XMLElement["RP", {}, {"81.4"}], 
                  XMLElement["RunRatio", {}, {"0.62"}], 
                  XMLElement["PAERAWinsOver162", {}, {"118.403"}], 
                  XMLElement["Games", {}, {"25.6"}], 
                  XMLElement["PAERAwins", {}, {"18.7"}], 
                  XMLElement["PAERAloses", {}, {"6.9"}], 
                  XMLElement["AVG", {}, {"0.208"}], 
                  XMLElement["OBA", {}, {"0.256"}], 
                  XMLElement["ShutOut", {}, {"1"}], 
                  XMLElement["H", {}, {"181"}], 
                  XMLElement["R", {}, {"76"}], 
                  XMLElement["ER", {}, {"66"}], 
                  XMLElement["HR", {}, {"21"}], 
                  XMLElement["K", {}, {"216"}], 
                  XMLElement["WP", {}, {"4"}], 
                  XMLElement["BLK", {}, {"0"}], 
                  XMLElement["HBP", {}, {"9"}], 
                  XMLElement["E", {}, {"4"}], 
                  XMLElement["Salary", {}, {"15714286"}], 
                  XMLElement["DollarsPerRun", {}, {"193002"}], 
                  XMLElement["PictureIndex", {}, {"7469"}]}], 
              XMLElement["PlayerRecord", {}, {XMLElement["PLAYER", {}, {"Tom Glavine"}], XMLElement["TEAM", {}, {"ATL"}], 
                  XMLElement["POS", {}, {"SP"}], 
                  XMLElement["GP", {}, {"37"}], 
                  XMLElement["GS", {}, {"35"}], 
                  XMLElement["STATUS", {}, {"A"}], 
                  XMLElement["W", {}, {"21"}], 
                  XMLElement["L", {}, {"9"}], 
                  XMLElement["S", {}, {"0"}], 
                  XMLElement["IP", {}, {"241.0"}], 
                  XMLElement["ERA", {}, {"3.40"}], 
                  XMLElement["ParkAdj", {}, {"0.98749"}], 
                  XMLElement["PAERA", {}, {"3.36"}], 
                  XMLElement["_90ERA", {}, {"5.94"}], 
                  XMLElement["_50ERA", {}, {"4.54"}], 
                  XMLElement["RPper9inn", {}, {"2.6"}], 
                  XMLElement["RP", {}, {"69.3"}], 
                  XMLElement["RunRatio", {}, {"0.57"}], 
                  XMLElement["PAERAWinsOver162", {}, {"103.724"}], 
                  XMLElement["Games", {}, {"26.8"}], 
                  XMLElement["PAERAwins", {}, {"17.1"}], 
                  XMLElement["PAERAloses", {}, {"9.6"}], 
                  XMLElement["AVG", {}, {"0.235"}], 
                  XMLElement["OBA", {}, {"0.287"}], 
                  XMLElement["ShutOut", {}, {"2"}], 
                  XMLElement["H", {}, {"222"}], 
                  XMLElement["R", {}, {"101"}], 
                  XMLElement["ER", {}, {"91"}], 
                  XMLElement["HR", {}, {"24"}], 
                  XMLElement["K", {}, {"152"}], 
                  XMLElement["WP", {}, {"0"}], 
                  XMLElement["BLK", {}, {"0"}], 
                  XMLElement["HBP", {}, {"4"}], 
                  XMLElement["E", {}, {"0"}], 
                  XMLElement["Salary", {}, {"9463237"}], 
                  XMLElement["DollarsPerRun", {}, {"136611"}], 
                  XMLElement["PictureIndex", {}, {"7641"}]}], 
              XMLElement["PlayerRecord", {}, {XMLElement["PLAYER", {}, {"Mike Hampton"}], XMLElement["TEAM", {}, {"NYM"}], 
                  XMLElement["POS", {}, {"SP"}], 
                  XMLElement["GP", {}, {"35"}], 
                  XMLElement["GS", {}, {"33"}], 
                  XMLElement["STATUS", {}, {"A"}], 
                  XMLElement["W", {}, {"15"}], 
                  XMLElement["L", {}, {"10"}], 
                  XMLElement["S", {}, {"0"}], 
                  XMLElement["IP", {}, {"217.2"}], 
                  XMLElement["ERA", {}, {"3.14"}], 
                  XMLElement["ParkAdj", {}, {"1.06200"}], 
                  XMLElement["PAERA", {}, {"3.33"}], 
                  XMLElement["_90ERA", {}, {"5.94"}], 
                  XMLElement["_50ERA", {}, {"4.54"}], 
                  XMLElement["RPper9inn", {}, {"2.6"}], 
                  XMLElement["RP", {}, {"63.0"}], 
                  XMLElement["RunRatio", {}, {"0.58"}], 
                  XMLElement["PAERAWinsOver162", {}, {"104.242"}], 
                  XMLElement["Games", {}, {"24.1"}], 
                  XMLElement["PAERAwins", {}, {"15.5"}], 
                  XMLElement["PAERAloses", {}, {"8.6"}], 
                  XMLElement["AVG", {}, {"0.229"}], 
                  XMLElement["OBA", {}, {"0.316"}], 
                  XMLElement["ShutOut", {}, {"1"}], 
                  XMLElement["H", {}, {"194"}], 
                  XMLElement["R", {}, {"89"}], 
                  XMLElement["ER", {}, {"76"}], 
                  XMLElement["HR", {}, {"10"}], 
                  XMLElement["K", {}, {"151"}], 
                  XMLElement["WP", {}, {"10"}], 
                  XMLElement["BLK", {}, {"0"}], 
                  XMLElement["HBP", {}, {"8"}], 
                  XMLElement["E", {}, {"2"}], 
                  XMLElement["Salary", {}, {"5750000"}], 
                  XMLElement["DollarsPerRun", {}, {"91298"}], 
                  XMLElement["PictureIndex", {}, {"7686"}]}]}], {}];\)\)

ExportString[data, "XML"]

errpart = First@SymbolicXMLErrors[data]

data[[Sequence @@ errpart]] // InputForm

Extra

Loading XML from the web

Although Import does not currently support retrieval of data over HTTP, it is possible to do so using the XML`Parser`XMLGet function.

Getting stock quotes from the internet

\(\(\(xmlquotes\)\(=\)\(XML`Parser`XMLGet["http://www.xmltoday.com/examples/stockquote/getxmlquote.vep?s=ba+lmt+ibm+int+amd+mmm"]\)\(\ \)\)\)

\(\(GetQuotes[xml_] := 
        Cases[xml, 
          XMLElement["stock_quote", _, {___, 
                XMLElement["symbol", _, {symbol_}], ___, 
                XMLElement["price", {"type" -> "ask", "value" -> v_}, {}], ___}] :> {symbol, ToExpression[v]}, 
          Infinity];\)\)

quotes = GetQuotes[xmlquotes]

<< Graphics`Graphics`

BarChart[#[[2]] & /@ quotes, 
        BarLabels -> (#[[1]] & /@ quotes), 
        TextStyle -> {FontSize -> 20}];

Call to action

Writing translators to consume and produce XML formats

There is an XML data format for representing almost every form of data.

Financial

Genetic

Graphical

Chemical

Astronomical

Publishing

Musical

Some are formally produced by standards bodies, while others are very informal.

If you are looking to access data encoded in one of these formats,consider writing a translator that builds on SymbolicXML to convert the data to an appropriate Mathematica representation and back. At Wolfram Research we have done this for MathML and NotebookML.

Mathematica is the ideal tool for expression manipulation!

Inventing your own XML formats

If you have data in Mathematica that you would like to share with people who don't use Mathematica, consider using XML to define a format for your data.  You can share your data without losing the structure that Mathematica provides.

Don't settle for data without structure!  Now the rest of the world can process the structure that Mathematica has always had.