1

I'm working on a service in which I pass a JSON request, I need to convert it to XML and them compare it to some XML schemas and then do something with it.

My problem is with the attributes. For example, my JSON request is:

{
"BookingSearch_IN": {
"MsgHeader": {      
  "MessageID": "ABC010101",
  "ContextRecord": {
    "ContextInfo": {
      "ItineraryDetails": {
        "ItinerarySeqNmbr": "1",
        "StartDate": "2017-04-01",
        "EndDate": "2017-04-14",            
        "LocationStart": {
          "LocationContext": "AIRPORT",
          "LocationCode": "MIA"
        },
        "LocationEnd": {
          "LocationContext": "AIRPORT",
          "LocationCode": "MIA"
        }
      },
      "ExtraInfoList": {
        "ExtraInfo": {
          "Category": "CRUISE",
          "Item": {
            "Code": "SHIP_CODE",
            "Value": "MAGIC"
          }
        }
      },
      "_ResType": "Vacation"
    }
  }
},
"_xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"_xmlns:cs": "http://MyCompany.com",
"_version": "6.66",
"__prefix": "cs"
  }
}

I'm using: XmlDocument doc = JsonConvert.DeserializeXmlNode(jsonObject); to convert it to XML. The xml result is:

<BookingSearch_IN>
<MsgHeader>
    <MessageID>ABC010101</MessageID>
        <ContextRecord>
            <ContextInfo>
                <ItineraryDetails>
                    <ItinerarySeqNmbr>1</ItinerarySeqNmbr>
                    <StartDate>2017-04-01</StartDate>
                    <EndDate>2017-04-14</EndDate>                       
                    <LocationStart>
                        <LocationContext>AIRPORT</LocationContext>
                        <LocationCode>MIA</LocationCode>
                    </LocationStart>
                    <LocationEnd>
                        <LocationContext>AIRPORT</LocationContext>
                        <LocationCode>MIA</LocationCode>
                    </LocationEnd>
                </ItineraryDetails>
                <ExtraInfoList>
                    <ExtraInfo>
                    <Category>CRUISE</Category>
                    <Item>
                        <Code>SHIP_CODE</Code>
                        <Value>MAGIC</Value>
                    </Item>
                    </ExtraInfo>
                </ExtraInfoList>
                <_ResType>Vacation</_ResType>
            </ContextInfo>
        </ContextRecord>
</MsgHeader>
<xsi>http://www.w3.org/2001/XMLSchema-instance</xsi><cs>http://MyCompany.com</cs><_version>6.66</_version><__prefix>cs</__prefix>
</BookingSearch_IN>

The result XML has the attributes of the root element at the end of the document, as another elements (between </MsgHeader> and </BookingSearch_IN>). My problem is that the service that validates this XML against other customers' XML checks these attributes in the root element. Here is how the code expects the XML to be:

    <?xml version="1.0" encoding="UTF-8"?>
<cs:BookingSearch_IN xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cs="http://MyCompany.com" version="6.66">
    <MsgHeader> 
        <MessageID>ABC010101</MessageID>
        <ContextRecord>
            <ContextInfo ResType="Vacation">
                <ItineraryDetails>
                    <ItinerarySeqNmbr>1</ItinerarySeqNmbr>
                    <StartDate>2017-04-01</StartDate>
                    <EndDate>2017-04-14</EndDate>                       
                    <LocationStart>
                        <LocationContext>AIRPORT</LocationContext>
                        <LocationCode>MIA</LocationCode>
                    </LocationStart>
                    <LocationEnd>
                        <LocationContext>AIRPORT</LocationContext>
                        <LocationCode>MIA</LocationCode>
                    </LocationEnd>
                </ItineraryDetails>
                <ExtraInfoList>
                    <ExtraInfo>
                        <Category>CRUISE</Category>
                        <Item>
                            <Code>SHIP_CODE</Code>
                            <Value>MAGIC</Value>
                        </Item>     
                    </ExtraInfo>
                </ExtraInfoList>
            </ContextInfo>          
        </ContextRecord>
    </MsgHeader>        
</cs:BookingSearch_IN>

The code fails because it expect the root element to be <cs:BookingSearch_IN xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cs="http://MyCompany.com" version="5.22">

.... any advise on how to handle this situation? or how to put those attributes back to where they belong in the root element?

Dan Field
  • 20,885
  • 5
  • 55
  • 71
Rolando F
  • 148
  • 3
  • 17

1 Answers1

2

NewtonSoft expects attributes to be prefixed with @, not _ or __, and expects prefixes to just be baked into the names. For example, if you can get your JSON to look like this:

{
    "cs:BookingSearch_IN": {
        "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
        "@xmlns:cs": "http://MyCompany.com",
        "@version": "6.66",
        "MsgHeader": {
            "MessageID": "ABC010101",
            "ContextRecord": {
                "ContextInfo": {
                    "@ResType": "Vacation",
                    "ItineraryDetails": {
                        "ItinerarySeqNmbr": "1",
                        "StartDate": "2017-04-01",
                        "EndDate": "2017-04-14",
                        "LocationStart": {
                            "LocationContext": "AIRPORT",
                            "LocationCode": "MIA"
                        },
                        "LocationEnd": {
                            "LocationContext": "AIRPORT",
                            "LocationCode": "MIA"
                        }
                    },
                    "ExtraInfoList": {
                        "ExtraInfo": {
                            "Category": "CRUISE",
                            "Item": {
                                "Code": "SHIP_CODE",
                                "Value": "MAGIC"
                            }
                        }
                    }
                }
            }
        }
    }
}

It will work correctly (note that you have to move those XMLNS's up to the top - if they stay where they are at the bottom, it drops the prefix for some reason).

If that's not possible, you'll either have to use a different serializer or write some custom logic to pre/post process your JSON or XML.

Dan Field
  • 20,885
  • 5
  • 55
  • 71
  • Since I needed to test my code, I googled some online tools to convert my XML sample to JSON and look if it works. I found out that there is no "standard" way to represent XML in JSON format. One of the websites converted my XML to JSON with the attributes just as the way you replied, right after the element but with the prefix "_". I think I can use that online tool and just replace the " _ " for "@". I didn't know NewtonSoft expected "@" for the attributes. Your answer solved my problem... thanks for the info! – Rolando F Mar 24 '17 at 14:44
  • I want to say that `DataContractJsonSerializer` uses the `_`s... But yeah, there's no standard, each serializer has its own method. – Dan Field Mar 24 '17 at 14:48