Dan
Dan

Reputation: 5986

Convert string to xml in c# gives whitespace error

I'm not a .NET dev but have a simple (or should be simple!) task to accomplish. I basically need to generate a chunk of XML from various string values and format this into a valid XML object in C#. The code I have is like this:

private XDocument BuildPayload(string weight, string fromCountryCode, string fromZipCode, string toCountryCode, string toZipCode, string serviceTypeCode, string packageTypeCode, string pickupTypeCode)
    {

        string upsAccessLiscenseNumber = "xxxxxxxxxxxxxxxx";
        string upsUserID = "xxxxxxxxxx";
        string upsPassword = "xxxxxxxxx";
        string unitOfMeasurementWeight = "LBS";

        StringBuilder sb = new StringBuilder();
        sb.Clear();
        sb.Append("<?xml version='1.0'?>");
        sb.Append(" <AccessRequest xml:lang='en-US'>");
        sb.Append("     <AccessLicenseNumber>").Append(upsAccessLiscenseNumber).Append("</AccessLicenseNumber>");
        sb.Append("     <UserId>").Append(upsUserID).Append("</UserId>");
        sb.Append("     <Password>").Append(upsPassword).Append("</Password>");
        sb.Append(" </AccessRequest>");
        sb.Append("<?xml version='1.0'?>");
        sb.Append(" <RatingServiceSelectionRequest xml:lang='en-US'>");
        sb.Append("     <Request>");
        sb.Append("         <TransactionReference>");
        sb.Append("             <CustomerContext>Rating and Service</CustomerContext>");
        sb.Append("             <XpciVersion>1.0001</XpciVersion>");
        sb.Append("         </TransactionReference>");
        sb.Append("         <RequestAction>Rate</RequestAction>");
        sb.Append("         <RequestOption>Shop</RequestOption>");
        sb.Append("     </Request>");
        sb.Append("     <PickupType>");
        sb.Append("         <Code>").Append(pickupTypeCode).Append("</Code>");
        sb.Append("     </PickupType>");
        sb.Append("     <Shipment>");
        sb.Append("         <Shipper>");
        sb.Append("             <Address>");
        sb.Append("                 <PostalCode>").Append(fromZipCode).Append("</PostalCode>");
        sb.Append("          <CountryCode>").Append(fromCountryCode).Append("</CountryCode>");
        sb.Append("             </Address>");
        sb.Append("         </Shipper>");
        sb.Append("         <ShipTo>");
        sb.Append("             <Address>");
        sb.Append("                 <PostalCode>").Append(toZipCode).Append("</PostalCode>");
        sb.Append("                 <CountryCode>").Append(toCountryCode).Append("</CountryCode>");
        sb.Append("             </Address>");
        sb.Append("         </ShipTo>");
        sb.Append("         <Service>");
        sb.Append("             <Code>").Append(serviceTypeCode).Append("</Code>");
        sb.Append("         </Service>");
        sb.Append("         <Package>");
        sb.Append("             <PackagingType>");
        sb.Append("                 <Code>").Append(packageTypeCode).Append("</Code>");
        //sb.Append("                   <Description>Package</Description>");
        sb.Append("             </PackagingType>");
        sb.Append("             <Description>Rate Shopping</Description>");
        sb.Append("             <PackageWeight>");
        sb.Append("                 <UnitOfMeasurement>");
        sb.Append("                 <Code>").Append(unitOfMeasurementWeight).Append("</Code>");
        sb.Append("                 </UnitOfMeasurement>");
        sb.Append("                 <Weight>").Append(weight).Append("</Weight>");
        sb.Append("             </PackageWeight>");
        sb.Append("         </Package>");
        sb.Append("         <ShipmentServiceOptions/>");
        sb.Append("     </Shipment>");
        sb.Append("</RatingServiceSelectionRequest>");
        XDocument doc = XDocument.Parse(sb.ToString());
        return doc;
    }

However, when I call this I get an error:

Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it.

I've found a couple of posts suggesting things (like putting the sb.Clear() in there) but nothing works. It seems to think there's some space at the top of the XML string, but I can't see that there is. The only slightly dodgy thing I can see is that there are two <?xml version='1.0'?> lines in there. This has come from the UPS docs though, and I have an old Classic ASP app that uses pretty much this exact same XML and it works fine, so I'm not sure that's the problem.

Can anyone point me in the right direction with this please?

Many thanks.

Upvotes: 3

Views: 814

Answers (4)

olegk
olegk

Reputation: 787

It's incorrect XML. XML should have only one root and one xml declaration.

Upvotes: 2

Mike Dinescu
Mike Dinescu

Reputation: 55760

Well, the XML that you are generating is definitely not a valid XML document. It's actually 2 XML documents, one after the other.

As a side note, you might want to use the .Net XmlWriter class for building the XML document as it is more expressive and might help you pinpoint any mistakes you are making in forming the document.

However, of this is supposed to be just a chunk of XML than what you really want is to parse it as a document fragment and remove the <?XML ... ?> declarations altogether.

Upvotes: 5

Philipp Sch
Philipp Sch

Reputation: 348

As far as I know there the line <?xml version='1.0'?> must be the first line in an XML document and there must be exactly one root node. You have no root node / or two root nodes: AccessRequest and RatingServiceSelectionRequest. It seems like you are just appending one xml doc to another.

You should put both nodes RatingServiceSelectionRequest and AccessRequest in one root node

Upvotes: 5

Joe Enos
Joe Enos

Reputation: 40413

You called it with the two declarations. You can only have one declaration and one root element in the document. You've got two separate documents there.

Anything that successfully reads that must not be checking for a valid XML document - maybe a simple reader that only reads one element at a time instead of an entire document.

Upvotes: 4

Related Questions