Json解组因字符无效而失败

问题描述:

Im having difficulties to unmarshal json content in golang. One of the fields in my object contains xml content and occasionally it will fail, claiming messages such as: invalid character '\x..' in string literal

I understand that this is as a result of control characters in my xml, but dont know how to handle it. I store my documents in mongoosejs and save the xml field as type String My struct Im trying to deserialize to is declared this way:

type A struct {
  Xml []byte `json:"xml"`
}

Unmarshaling is done the following way:

var xml A
err := json.Unmarshal(content, &xml)

Since JSON cannot contain any control characters, I found the most convenient solution to simply convert the xml data to base64, e.g:

// before sending in javascript
a.xml = new Buffer(a.xml).toString('base64')

Then, In golang side:

// Declare a new type for custom unmarshaling
type XmlB64 []byte
func (b *XmlB64) UnmarshalJSON(data []byte) error {
    if b == nil {
        return fmt.Errorf("UnmarshalJSON on nil pointer")
    }

    if len(data) == 0 {
        return nil
    }

    if x, err := base64.StdEncoding.DecodeString(string(data)); err != nil {
        return err
    } else {
        *b = x
    }

    return nil
}

After doing that, Unmarshalling base64 content is done without doing anything special in the code. We first change our struct:

type A struct {
  Xml XmlB64 `json:"xml"`
}

Unmarshal:

var xml A
err := json.Unmarshal(content, &xml)

The JSON package encodes and decodes []byte values as base-64 encoded strings. If the XML is not base-64 encoded, then change the type to string to avoid the encoding.

type A struct {
  Xml string `json:"xml"`
}

Another solution is to encode the XML as base64 and leave the type as defined in the question.

If base64 encoding is not the issue, then print the offset of the error and check the JSON text at that offset.

err := json.Unmarshal(content, &xml)
switch err := err.(type) {
case *json.SyntaxError:
   fmt.Printf("syntax error at offset %d: %v
", err.Offset, err)
case *json.UnmarshalTypeError:
   fmt.Printf("type error at offset %d: %v
", err.Offset, err)
case nil:
   // no error
default:
   fmt.Printf("error %v
", err)
}

In general, XML text cannot be used as a JSON string without quoting.