Mark Wilson I am the creator of TopXML. I am available for international and local (Australia) contracts. I am a Solution Architect/Business Analyst. I have worked in IT in several countries (NZ, Australia, South Africa, UK) building and training teams for government and very large non-governmental organizations. I am ex-Microsoft Consulting Services. I wrote the first book on Microsoft XML published in 2000 called XML Programming with VB and ASP. Most recently I have been building tools for the SEO industry. Ask me for a 37 point SEO health-checkup for your website.
There are several ways we can declare namespaces and prefixes at
runtime. The XmlSerializer itself allows us to define a global default
namespace for all objects it processes as well as supplying prefix declarations
for namespaces references by the serialized objects. While we can declare
namespaces at runtime by dynamically attaching XML serialization attributes, there
are hardly any use-cases that warrant doing so.
You can also leverage the namespace prefix support built into the
XmlTextWriter if you are serializing more than one object into the same
XmlTextWriter instance, but in this section we focus on the capabilities of the
XmlSerializer.
We can declare a default namespace for all serialized and
deserialized objects by passing the namespace’s URI to the XmlSerializer
constructor as shown in the following fragment.
public static void SerializeACarWithDefaultNamespace( Car aCar,
XmlWriter writer )
{
XmlSerializer xs = new
XmlSerializer( typeof( ParkingLot ), "urn:christoph-cars" );
xs.Serialize( writer,
aCar );
}
The XmlSerializer adds the declaration for this namespace to the
output of all serialized objects that do not declare themselves a namespace
through and XmlRoot attribute. Likewise, serialized objects of all classes that
do not explicitly declare a different namespace have to be part of the default
namespace to be properly deserialized.
Declaring XML namespaces at runtime bears a distinct advantage
over declaring them at compile time. Imagine if we defined a namespace prefix
inside a class, but that prefix is already in use for a different namespace in
the document we are serializing into. While it is technically possible to
declare the same prefix for different namespaces as long as the scoping of the
declarations is clear, it is very confusing to a human reader and negates the
use of prefixes altogether. Furthermore, the XmlSerializer does allow
conflicting prefix declarations in the same scope, which makes declaring
namespaces in class code downright dangerous.
We can declare prefixes at runtime by setting up an
XmlSerializerNamespaces dictionary with the prefix-to-namespace mappings, just
like we did when the serialized class itself contained the dictionary. This time we supply the dictionary to the
XmlSerializer directly, through one of the overloaded version of the
Serialize() method. The XmlSerializer will declare all the prefixes in the
dictionary at the root element of the serialized object, which means that these
prefix declarations are only valid for this particular call of Serialize(). You
will have to pass them again to subsequent calls if you want to repeat the
declarations, even if the serialized object is of the same type.
NOTE: The prefix declarations will not be repeated if they are
already defined in the current scope.
16
Listing 10.12 Declaring
namespace prefixes at runtime.
public static void SerializeACarWithQualifiedNames( Car aCar,
XmlWriter writer )
{
XmlSerializer xs = new XmlSerializer( typeof(
ParkingLot ), "urn:christoph-cars");
XmlSerializerNamespaces
namespaces =
new
XmlSerializerNamespaces();
namespaces.Add(
"md", "urn:cars-models" );
namespaces.Add(
"mk", "urn:cars-makes" );
xs.Serialize( writer,
aCar, namespaces );
}
The code snippet above demonstrates how to set up the
XmlSerializerNamespaces collection to declare a set of prefixes. The XML
document fragment below shows the output from the Serialize() call.
17
Listing 10.13 The output
of listing 10.12, the namespace prefixes are declared at runtime.
NOTE: By default the XmlSerializer creates the namespace declarations
xmlns:xsd=http://www.w3.org/2001/XMLSchema and
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance at the root of each serialized element[6] to support data type declarations. If we provide a namespaces collection to the Serialize()
method, it will generate declarations for the namespaces in the collection only. We can leverage this if
we need to omit the default declarations and by passing an empty
collection. If the serialized content requires these namespaces the
XmlSerializer declares them locally.