views:

1428

answers:

2

The Xml response I receive is as follows:

<response>
    <item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="java:com.someDomain.item">
     <name>some name</disc-name>
     <description>some description</disc-desc>
    </item>
    <item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="java:com.someDomain.item">
         <name>some name</disc-name>
         <description>some description</disc-desc>
    </item>
    <otherValue>12.1</otherValue>
</response>

My class is decorated as such:

[XmlElement("item")]
public Item[] Items{get;set;}
[XmlElement("otherValue")
public string OtherValue{get;set;}

When I attempt to deserialize the above Xml to the class described, I receive an error of "Namespace prefix 'java' is not defined". Adding the "namespace" attribute to the class resolves the parsing error(however, the xml is then distorted from the original).

ie

[XmlElement(ElementName="item",Namespace="java")]

How should I be decorating a given property to match up with a new namespace? Or, how do I correctly define the namespace?

I'm not 100% on using a stock array for my enumerable section either, but I think the namespace issue takes precident at the moment. Any insight or thoughts are greatly appreciated!

UPDATE:

I think the question is better rephrased now that I've gone back and forth a bit:

How do you use an XmlElementAttribute(or other attribute) to have a class that can serialize into the item snippet above, including the xsi tags?

As for my particular problem, I've realized since the Xml response is out of my control, I don't need the xsi attributes to begin with. To workaround the serialization issue, I'm simply doing the following(XmlElement element contains the original document above):

foreach(XmlNode node in element)
node.Attributes.RemoveAll();

I'm only noting my personal workaround as this is not actually a solution.

+1  A: 

You were right the first time. "java" is not a namespace. It's a namespace prefix. That's an abbreviation of the namespace, for use in the XML. Otherwise, the actual namespace would need to be repeated wherever you currently see "java:".

You can use List<Item> instead of Item[].

John Saunders
That makes sense to me, not having "java" listed as a namespace. However, on deserialization of the incoming Xml response, I receive the error of "Namespace prefix 'java' is not defined".
Alexis Abril
I assumed it was in the rest of the document you didn't show. Can you post the entire XML document? If `java:` isn't defined, there's nothing you can do about it -it's just bad XML.
John Saunders
There's multiple "othervalues" added on to the sample above, but yeah, other than the header xml version tag, that's the entire document. This is being received as a REST response, so I don't have control over the Xml headed my way, just attempting to convert it to a usable object.
Alexis Abril
If there's no "xmlns:java=something", then it's just plain bad XML.
John Saunders
It should be noted however that a workaround would be to manually insert a namespace node into the root element, so that `java` prefix gets associated some namespace URI (doesn't really matter which, so long as it's there - you could e.g. use `urn:java`).
Pavel Minaev
It's true, that would be a workaround. However, since this XML wouldn't work even in the system it _came_ from, I'd suggest that the OP first find out why. It's possible that it's a simple bug on the other end, in which case a workaround would not only be unnecessary, but would also be a disservice to those who are sending the XML.
John Saunders
A: 

Unfortunately this is valid XML, and completely conforms to the XML Standard. It validates, it's correct and it's complete.

The problem you're having is in the deserialization, which is not a part of the XML Standard and is related to how .NET maps declared XML types to internal CLR types.

The xsi:type is a namespace reference and is intended to allow XML documents to substitute a derived type from another namespace for the declared type in the schema.

I know from my own experience that coders tend to react in shock that this sort of thing is even legal, much less correct XML. It basically hijacks your schema.

You do not need even need to include the foreign namespace in order for this to be considered correct.

(see this article for more ranting on this subject: http://norman.walsh.name/2004/01/29/trainwreck)

Now, as to how to handle your stated problem: deserialize this mess. 1) process the xml text and remove the xsi-types declaration and hope there are no fields declared that extend the base type. 2) declare a type that derives from your base type in the schema.

This looks like the following:

// note this "XmlIncludeAttribute" references the derived type.
// note that in .NET they are in the same namespace, but in XML they are in different namespaces.
[System.Xml.Serialization.XmlIncludeAttribute(typeof(DerivedType))]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://BaseNameSpace")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://BaseNameSpace", IsNullable=true)]
public partial class MyBaseType : object
{
...
}

/// <remarks/>
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://DerivedNameSpace")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://DerivedNameSpace", IsNullable=true)]
public partial class DerivedType: MyBaseType 
{
...
}

This is only a rough outline, hopefully enough to get you started. Note that this is not an easy problem to solve progmatically because it's always possible for someone to feed you XML and it will validate but not deserialize properly.

Oplopanax