简体   繁体   中英

ajv - validate JSON that has line breaks?

What is the correct way of validating a JSON document with values that contains line breaks, \\n , using ajv ?

Simplified example:

  • A JSON schema defines a document that has a single property called key that accepts a string value (the schema was inferred by submitting {"key":"value"} to https://jsonschema.net )
  • A JavaScript object is serialized using JSON.stringify() . As a consequence, newline characters such as \\n are escaped, ie \\\\n
  • Ajv's validate() function is called to validate the serialized string

Snippet:

// JSON schema definition
const schema = {
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "required": [
    "key"
  ],
  "properties": {
    "key": {
      "$id": "#/properties/key",
      "type": "string",
      "title": "The Key Schema",
      "default": "",
      "examples": [
        "value"
      ],
      "pattern": "^(.*)$"
    }
  }
};

// a JavaScript object that has a line break
const data = { key: 'a string\nwith a line break' };

// serialize to JSON
const json = JSON.stringify(data);
// json === "{\"key\":\"a string\\nwith a line break\"}"

// validate
const Ajv = require('ajv');
const ajv = new Ajv();
const valid = ajv.validate(schema, json);

// print results
console.info('Valid:', valid);
console.info('Errors:', ajv.errors);

I expected this to work, but it turns out that validation fails during execution:

Valid: false
Errors: [
  {
    keyword: 'type',
    dataPath: '',
    schemaPath: '#/type',
    params: { type: 'object' },
    message: 'should be object'
  }
]

To my understanding this is because json is a string whereas the schema definition states that it should be an object .

I have also tried to deserialize the JSON string, eg ajv.validate(schema, JSON.parse(json)); , but it also fails:

Valid: false
Errors: [
  {
    keyword: 'pattern',
    dataPath: '.key',
    schemaPath: '#/properties/key/pattern',
    params: { pattern: '^(.*)$' },
    message: 'should match pattern "^(.*)$"'
  }
]

This makes sense because JSON.parse() returns a JavaScript object which is not JSON (eg keys are not quoted and importantly for this question string values with unescaped \\n characters).

Dependency: ajv 6.10.0

I turns out that I used the wrong regex pattern. . matches any character except newline . To work around this, I changed the pattern to [\\s\\S] , where the \\s character class matches "any whitespace character" and \\S character class is its negation, "any non-whitespace character". Moreover, since the pattern is defined in the value of a JavaScript object, the back slashes in \\s and \\S also needs to be escaped, ie [\\\\s\\\\S] . Consequently, the schema definition should be as follows:

const schema = {
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "required": [
    "key"
  ],
  "properties": {
    "key": {
      "$id": "#/properties/key",
      "type": "string",
      "title": "The Key Schema",
      "default": "",
      "examples": [
        "value"
      ],
      "pattern": "^([\\s\\S]*)$"
    }
  }
};

See also this answer and the online regex tester

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM