.NET Questions (CLOSED)

Questions and Answers on any aspect of .NET. Now closed.

This discussion group is now closed.

Have a question about .NET development? Try stackoverflow.com, a worldwide community of great developers asking and answering questions 24 hours a day.

The archives of .NET Questions contain years of Q&A. Even older .NET Questions are still online, too.

XML Attribute changed when converting XmlDocument to string

Background:
Using HTTPS/XML to talk to FedEx as per their documentation. C# application.

For the most part, the communication is working, except for this bit of code. It generates the beginning elements of the XML document:
_rootElement = _theDocument.CreateElement(_rootKey);
_rootElement.SetAttribute("xmlns:api", "http://www.fedex.com/fsmapi");
_rootElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
_rootElement.SetAttribute("xsi:noNamespaceSchemaLocation", _rootKey + ".xsd");
_theDocument.AppendChild(_rootElement);


The last attribute is supposed to be "xsi:noNamespaceSchemaLocation", but when the document is written to a string, the "xsi" part is stripped. The other attributes are not molested like this one.

The FedEx server is requiring this "xsi" prefix or I get an error. I've been able to replace the xsi before I send the data and the program works.

Any idea why the StringWriter/XmlWriter would do this?

Keith
Keith Murray Send private email
Tuesday, January 23, 2007
 
 
It's because you're doing it wrong.

FexEx doesn't (or shouldn't be, or they're screwing it up too) require an "xsi:" prefix. What they require is that this attribute be in the correct namespace. The actual prefix doesn't matter.

The prefix you tried to sandwich in there is being stripped because what you're actually trying to do is add an attribute  with no namespace that contains a ":", which is illegal. Ideally, it should probably throw rather than silently fail.

What you really want to do is:

string apiNS = "http://www.fedex.com/fsmapi";
string xsiNS = "http://www.w3.org.2001/XMLSchema-instance";

_rootElement = _theDocument.CreateElement(_rootKey);
_rootElement.SetAttribute( "noNamespaceSchemaLocation", xsiNS, _rootKey + ".xsd" );
_theDocument.AppendChild(_rootElement);

You don't need to explicitly add the namespace prefixes, the xml writer will generate prefixes for it when it outputs the DOM.
Chris Tavares Send private email
Tuesday, January 23, 2007
 
 
When I use your code, the apiNS constant is not used.

According to FedEx, the root tag should look like this:

<FDXSubscriptionRequest  xmlns:api="http://www.fedex.com/fsmapi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="FDXSubscriptionRequest .xsd">

My code causes the tag to look like this:

<FDXSubscriptionRequest xmlns:api="http://www.fedex.com/fsmapi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
noNamespaceSchemaLocation="FDXSubscriptionRequest .xsd">

Your code makes the tag look like:
<FDXSubscriptionRequest d1p1:noNamespaceSchemaLocation="FDXSubscriptionRequest.xsd" xmlns:d1p1="http://www.w3.org.2001/XMLSchema-instance">

Both my code and your code cause an error to be returned:
"org.xml.sax.SAXParseException: Element type "FDXSubscriptionRequest" must be declared.". If I add the "xsi" prefix, all is well.

According to your explanation, would have to say that FedEx is not following the standads. But I'm stuck because I doubt I will be able to get them to change their code.

Keith
Keith Murray Send private email
Wednesday, January 24, 2007
 
 
Chris's answer is correct but he didn't include the lines to add the namespace attributes.  This works:

string apiNS = "http://www.fedex.com/fsmapi";
string xsiNS = "http://www.w3.org.2001/XMLSchema-instance";

_rootElement = _theDocument.CreateElement(_rootKey);
_rootElement.SetAttribute("xmlns:api", apiNS);
_rootElement.SetAttribute("xmlns:xsi", xsiNS);
_rootElement.SetAttribute( "noNamespaceSchemaLocation", xsiNS, _rootKey + ".xsd" );
_theDocument.AppendChild(_rootElement);
SomeBody Send private email
Wednesday, January 24, 2007
 
 
Let me ask you a question. Does the correct tag look like this (as you stated):

<FDXSubscriptionRequest  xmlns:api="http://www.fedex.com/fsmapi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="FDXSubscriptionRequest .xsd">

or does it actually look like this:

<api:FDXSubscriptionRequest  xmlns:api="http://www.fedex.com/fsmapi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="FDXSubscriptionRequest .xsd">

or does it look like this:

<FDXSubscriptionRequest 
xmlns="http://www.fedex.com/fsmapi"
xmlns:api="http://www.fedex.com/fsmapi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="FDXSubscriptionRequest .xsd">

The question here is about what xml namespace the FDXSubscriptionRequest element is in. The first one puts the element into the "unnamed" namespace. The second and third both put it in the "http://www.fexed.fsmapi" namespace, first by using an explicit namespace declaration, and the second by using a default XML namespace.

I hate to think that an org as big as FedEx is this fucked up about XML; this kind of thing destroys the interoperability that is the whole reason XML is used for this stuff in the first place.

So, can I suggest one more tweak on my original attempt? Try this:

string apiNS = "http://www.fedex.com/fsmapi";
string xsiNS = "http://www.w3.org.2001/XMLSchema-instance";

_rootElement = _theDocument.CreateElement(_rootKey, apiNS); // <-- Add namespace to root element
_rootElement.SetAttribute( "noNamespaceSchemaLocation", xsiNS, _rootKey + ".xsd" );
_theDocument.AppendChild(_rootElement);

and see what happens.
Chris Tavares Send private email
Wednesday, January 24, 2007
 
 
Somebody,
Your tweak to Chris's code causes it to now generate the correct header (or at least Fedex's version of correct).

Chris,

As cut from the FedEx documentation, this is what the first part of the XML message should look like:

<?xml version="1.0" encoding="UTF-8" ?>
<FDXSubscriptionRequest xmlns:api="http://www.fedex.com/fsmapi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="FDXSubscriptionRequest.xsd">

I made the second change you mention which caused a radically different header and I caused FedEx to puke. I aagree the FedEx should be more in line with standards since the ability to do web services like this makes it a great add-on to any site that does shipping.

Thanks for all the XML help.
Keith
Keith Murray Send private email
Thursday, January 25, 2007
 
 
I am having similar issues....the organization I work for has an xml import tool.  The start element for the xml document is supposed to look like this

<records schema_revision="300_108" xmlns:xsi="http://www.w3.org/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.bowmansystems.com/schemas/sp_3.08.00/sp.xsd">

I am using an XmlWriter object to attempt to generate this but cant get it just right.  I assume it is because it should not be in that format. 

Here is the code I am using:

using (XmlWriter writer = XmlWriter.Create("providers.xml", this.xmlWriterSettings))
            {
                // --- Write XML provider data. 
                writer.WriteStartElement("records", "http://www.w3.org/2001/XMLSchema-instance");
                writer.WriteAttributeString("schema_revision", "300_108");
                writer.WriteAttributeString("noNamespaceSchemaLocation", "xsi",  "http://bowmansystems.com/schemas/sp_3.08.00/sp.xsd");
                writer.WriteEndElement();
                writer.Flush();
            }

The results:

<?xml version="1.0" encoding="utf-8"?>
<records schema_revision="300_108" p1:noNamespaceSchemaLocation="http://bowmansystems.com/schemas/sp_3.08.00/sp.xsd" xmlns:p1="xsi" xmlns="http://www.w3.org/2001/XMLSchema-instance" />

I do not want the xsi prefix attached to the records tag...also I find it odd that the end element did not write out.

Any help you could give me would help greatly.  I am fairly new to this and still learning.  Also, if our format is incorrect let me know.
Thomas Fitzgerald Send private email
Monday, February 05, 2007
 
 
I have changed the code to read:

using (XmlWriter writer = XmlWriter.Create("providers.xml", this.xmlWriterSettings))
            {
                // --- Write XML provider data. 
                writer.WriteStartElement("xsi", "records", "http://www.w3.org/2001/XMLSchema-instance");
                writer.WriteAttributeString("schema_revision", "300_108");
                writer.WriteAttributeString("xsi", "noNamespaceSchemaLocation", "http://www.w3.org/2001/XMLSchema-instance", "http://bowmansystems.com/schemas/sp_3.08.00/sp.xsd");
                writer.WriteEndElement();

                writer.Flush();
            } 

This almost does the job...Results:

<xsi:records schema_revision="300_108" xsi:noNamespaceSchemaLocation="http://bowmansystems.com/schemas/sp_3.08.00/sp.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

however, is there a way to get the xml to write out without the xsi prefix on the records tag?
Thomas Fitzgerald Send private email
Monday, February 05, 2007
 
 
Yes.

  // the namespace we'll be using
  string ns = "http://www.w3.org/2001/XMLSchema-instance";
  // write the "records" element in no namespace
  xw.WriteStartElement("records");
  // write the "schema_revision" attribute in no namespace
  xw.WriteAttributeString("schema_revision", "300_108");
  // write the XML-Schema namespace declaration and associate the "xsi" prefix with the namespace
  xw.WriteAttributeString("xmlns", "xsi", null, ns);
  // write the attribute string and put it in the XML-Schema namespace
  xw.WriteAttributeString("noNamespaceSchemaLocation", ns, "http://bowmansystems.com/schemas/sp_3.08.00/sp.xsd");

Wait, I hear you asking.  How do I specify the "xsi" prefix on the attribute?  You don't have to.  In fact, you *shouldn't*.  The prefix is *not significant*. 

What's significant is that the attribute belongs to the namespace, and that the most recent declaration of that namespace said to use "xsi" as its prefix.

The first thing that you have to learn when you're learning XML namespaces is that the prefix is *nothing*.  You *do not care* about the prefix.  All of these are *exactly equivalent* from an XML processing standpoint:

  <foo xmlns="bar"/>
  <x:foo xmlns:x="bar"/>
  <bat:foo xmlns:bat="bar"/>

If the document you tried to import into that program began with an element like this it would work:

<records schema_revision="300_108" xmlns:freeatlast="http://www.w3.org/XMLSchema-instance" freeatlast:noNamespaceSchemaLocation="http://www.bowmansystems.com/schemas/sp_3.08.00/sp.xsd">

If you are asking yourself "why isn't my program writing the right prefixes?" you are asking the wrong question; the question you should be asking is "why is my program creating elements and/or attributes in the wrong namespaces?"  Which will lead you to "Have I told the XmlWriter what namespaces I'm using yet?" and "Am I specifying the right namespace when I write the attribute and/or element?"

Hope this helps.  Namespaces are an incredible bewildering pain in the ass until you have the epiphany, and then they go back to being a necessary evil.
Robert Rossney Send private email
Thursday, February 15, 2007
 
 
Also:

I just looked at FedEx's API documentation.  What the hell?  Why on earth do they require a namespace declaration in the root element of every message and then NEVER USE IT?  What's the point of a namespace with no names in it?

It's hard for me to believe that they just stuck it on there because someone somewhere thought they ought to have a namespace for their stuff, and the developers didn't really understand what they were doing but said OK, we'll put a namespace declaration on our messages.
Robert Rossney Send private email
Thursday, February 15, 2007
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz