First time here? Check out the site's "greatest hits" or read a post from the archives. Feel free to leave a comment or ask a question, and consider subscribing to the latest posts via RSS or e-mail. Thanks for visiting!
« Visual Studio Team System and Pricing - ... | Main | Hanselingo - The Language of the Hanselm... »

I'm ashamed to even post this, as Dare and Oleg will likely balk at the audacity and pure poo of the solution.

That said, sometimes you have to support a legacy evil, er, solution and one's (mine) overdeveloped sense of code smell must be supressed.

So, there's some XML, it's as a schema and it's cool and strongly typed. It might look something like:

<?xml version="1.0" encoding="utf-16"?><ns0:SignOnResponse xmlns:ns0="http://www.corillian.com/Voyager/Authentication/Messages/2004/05"><ns1:Header xmlns:ns1=http://www.corillian.com/operations/2004/11">
<ns1:Something>somethingCoolio</ns1:Something>
...blah blah blah...
</ns0:SignOnResponse>

You get the idea...it's generated, but it's legit. Here's the weird part...for a legacy app, another XML Document (arguably a Fragment) is "tunnelled" within one of the the larger document's elements:

<ns1:Something><![CDATA[<holycrap><sweetlord>it's another xml document! hiding inside! Wow, it has no namespace? Oy.</sweetlord></holycrap>]]</ns1:Something>

Notice above that there's another entirely different document inside the larger one.  Additionally the fragment has a root node of "sweetlord" perhaps I want it to be deserialized into a "SomethingType." Since "SomethingType" was defined in XSD and generated earlier, I can't change it's [XmlRoot] without editing the generated code.

But, I can override it. So, this technique below shows two things.

  • Taking an Xml fragment that has no namespace and fooling the XmlSerializer (or any XmlTextReader consumer) into thinking it does using Clemen's/Chris's (dasBlog's/BlogX's) XmlNamespaceUpgrading Reader.
  • Using XmlAttributeOverrides to force the XmlSerializer to "no no, use THIS XmlRootAttribute!"
// myLargerResponse was deserialized from Xml.

// The Something property is a string containing an Xml Fragment

// as shown above. That fragment has no namespace, but there is a

// generated object WITH a namespace that it could deserialize into

// (it matches the "data contract.")

string tunnelledString = myLargerResponse.Something;

if(savedSerializer == null)

{

    XmlRootAttribute xra = new XmlRootAttribute("holycrap");

    xra.Namespace = "http://www.corillian.com/something/messages/2004/05";

 

    XmlAttributes attrs = new XmlAttributes();

    attrs.XmlRoot = xra;

 

    XmlAttributeOverrides over = new XmlAttributeOverrides();

    over.Add(typeof(SomethingType),attrs);

 

    savedSerializer = new XmlSerializer(

            typeof(SomethingType),

            over);

}

SomethingType info = savedSerializer.Deserialize(

        new XmlNamespaceUpgradeReader(

            new StringReader(tunnelledString),

            String.Empty,

            "http://www.corillian.com/something/messages/2004/05"))

        as SomethingType;

Here's the XmlNamespaceUpgradeReader. Notice that it's used above passing in String.Empty as the oldNamespaceUri, and the namespace we WISH it had as the newNamespaceUri. That's the namespace we told the XmlSerializer in the AttributeOverrides.

Note also that we save away the XmlSerializer because of the XmlSerializer leak for its complex constructor overrides. As an alternative to saving it off, we could use the very cool Mvp.Xml.XmlSerializerCache.

public class XmlNamespaceUpgradeReader : XmlTextReader

{

    string oldNamespaceUri;

    string newNamespaceUri;

 

    public XmlNamespaceUpgradeReader( TextReader reader, string oldNamespaceUri, string newNamespaceURI ):base( reader )

    {

        this.oldNamespaceUri = oldNamespaceUri;

        this.newNamespaceUri = newNamespaceURI;

    }

 

    public override string NamespaceURI

    {

        get

        {

            // we are assuming XmlSchemaForm.Unqualified, therefore

            // we can't switch the NS here

            if ( this.NodeType != XmlNodeType.Attribute &&

                base.NamespaceURI == oldNamespaceUri )

            {

                return newNamespaceUri;

            }

            else

            {

                return base.NamespaceURI;

            }

        }

    }

}

 

Tracked by:
"Using the XmlSerializer to Read and Write XML Fragments" (ComputerZen.com - Sco... [Trackback]
"Leaning on the Language and Leaning on the Libraries" (ComputerZen.com - Scott ... [Trackback]
"XmlValidatingReader problems over derived XmlReaders" (ComputerZen.com - Scott ... [Trackback]


Wednesday, March 23, 2005 6:58:03 PM (Pacific Standard Time, UTC-08:00)
You should give this a name and release an open source implementation of it - and support Eclipse. This is all wrong, man.
Comments are closed.

Contact

Sponsors

Hosting By

On this page...

Tags

Calendar

<December 2008>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Archives

Google Ads