Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions schema/json/metaschema-datatypes.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@
"pattern": "^-?P([0-9]+D(T(([0-9]+H([0-9]+M)?(([0-9]+|[0-9]+(\\.[0-9]+)?)S)?)|([0-9]+M(([0-9]+|[0-9]+(\\.[0-9]+)?)S)?)|([0-9]+|[0-9]+(\\.[0-9]+)?)S))?)|T(([0-9]+H([0-9]+M)?(([0-9]+|[0-9]+(\\.[0-9]+)?)S)?)|([0-9]+M(([0-9]+|[0-9]+(\\.[0-9]+)?)S)?)|([0-9]+|[0-9]+(\\.[0-9]+)?)S)$"
},
"DecimalDatatype": {
"description": "A real number expressed using a whole and optional fractional part separated by a period.",
"type": "number",
"pattern": "^(\\+|-)?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)$"
"description": "A real number expressed using a whole and optional fractional part separated by a period, with optional exponential notation. No leading '+' is allowed.",
"type": "number"
},
"EmailAddressDatatype": {
"description": "An email address string formatted according to RFC 6531.",
Expand Down
18 changes: 8 additions & 10 deletions schema/xml/metaschema-datatypes.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,15 @@

<xs:simpleType name="DecimalDatatype">
<xs:annotation>
<xs:documentation>A real number expressed using a whole and optional fractional part
separated by a period.</xs:documentation>
<xs:documentation>
A real number expressed using a whole and optional fractional part
separated by a period, with optional exponential notation.
No leading '+' is allowed. Leading zeros are not allowed except
for the integer 0 itself or numbers less than 1 (e.g., 0.5).
</xs:documentation>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</xs:annotation>
<xs:restriction base="xs:decimal">
<xs:pattern value="\S(.*\S)?">
<xs:annotation>
<xs:documentation>This pattern ensures that leading and trailing whitespace is
disallowed. This helps to even the user experience between implementations
related to whitespace.</xs:documentation>
</xs:annotation>
</xs:pattern>
<xs:restriction base="xs:double">
<xs:pattern value="-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?"/>
</xs:restriction>
</xs:simpleType>

Expand Down
57 changes: 57 additions & 0 deletions test/decimal-type/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Decimal Datatype Test Cases

This directory contains test schemas and content examples to validate the decimal datatype behavior as defined in PR #135.

## Schemas

- `decimal-test.xsd` - XML Schema with inline DecimalDatatype using pattern `-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?` and base type `xs:double`
- `decimal-test.json` - JSON Schema with inline DecimalDatatype using `type: "number"`

## Expected Behavior Matrix (Tested)

| Test Case | Example | JSON | XML |
|-----------|---------|:----:|:---:|
| Integers | `12` | ✓ | ✓ |
| Decimals | `12.34` | ✓ | ✓ |
| Positive with leading + | `+12.34` | ✗ | ✗ |
| Exponential notation | `1e3`, `1E+4`, `-2.5e-10` | ✓ | ✓ |
| Leading zeros | `01.23` | ✗ | ✗ |
| No leading digit | `.47` | ✗ | ✗ |
| Trailing decimal point | `123.` | ✗ | ✗ |
| Leading/trailing whitespace | ` 12.34 ` | ✓ | ✓ |

**Legend:** ✓ = Valid, ✗ = Invalid

### Notes

Both JSON and XML ignore/normalize whitespace around numeric values, so leading/trailing whitespace is accepted in both formats.

## Test Files

### XML Test Cases

- `xml-valid-cases.xml` - Contains values that SHOULD pass XML Schema validation
- `xml-invalid-cases.xml` - Contains commented-out invalid cases for individual testing

### JSON Test Cases

- `json-valid-cases.json` - Contains values that SHOULD pass JSON Schema validation
- `json-invalid-cases.json` - Documents invalid cases (many cannot be represented in valid JSON syntax)

## Key Differences Between JSON and XML

1. **Whitespace Handling**: Both XML Schema and JSON ignore whitespace around numeric values. XML Schema applies whitespace normalization (collapse) for `xs:double` before pattern matching. JSON ignores whitespace around values during parsing.

2. **Syntax Restrictions**: JSON syntax itself prohibits leading `+`, leading zeros (e.g., `01.23`), `.47`, and `123.` formats, making these parse errors rather than validation errors. The XML pattern explicitly rejects these as well.

## Running Validation Tests

### XML Validation (using xmllint)
```bash
xmllint --schema decimal-test.xsd xml-valid-cases.xml --noout
```

### JSON Validation (using ajv-cli)
```bash
ajv validate -s decimal-test.json -d json-valid-cases.json
```
Binary file added test/decimal-type/XmlValidator.class
Comment thread
david-waltermire marked this conversation as resolved.
Outdated
Binary file not shown.
29 changes: 29 additions & 0 deletions test/decimal-type/XmlValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
import java.io.File;

public class XmlValidator {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: java XmlValidator <schema.xsd> <document.xml>");
System.exit(1);
}

String schemaPath = args[0];
String xmlPath = args[1];

try {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new File(schemaPath));
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File(xmlPath)));
System.out.println(xmlPath + " is VALID");
} catch (Exception e) {
System.out.println(xmlPath + " is INVALID: " + e.getMessage());
System.exit(1);
}
}
}
38 changes: 38 additions & 0 deletions test/decimal-type/decimal-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://csrc.nist.gov/ns/metaschema/test/decimal/decimal-test-schema.json",
"$comment": "Schema for testing decimal datatype validation",
"type": "object",
"properties": {
"decimal-tests": {
"type": "object",
"properties": {
"test-cases": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"description": {
"type": "string"
},
"expected": {
"type": "string",
"enum": ["valid", "invalid"]
},
"value": {
"description": "A real number expressed using a whole and optional fractional part separated by a period, with optional exponential notation. No leading '+' is allowed.",
"type": "number"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
},
"required": ["id", "description", "expected", "value"]
}
}
},
"required": ["test-cases"]
}
},
"required": ["decimal-tests"]
}
46 changes: 46 additions & 0 deletions test/decimal-type/decimal-test.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:m="http://csrc.nist.gov/ns/metaschema/test/decimal"
targetNamespace="http://csrc.nist.gov/ns/metaschema/test/decimal"
elementFormDefault="qualified">

<!-- Root element for testing -->
<xs:element name="decimal-tests">
<xs:complexType>
<xs:sequence>
<xs:element name="test-case" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="value">
<xs:simpleType>
<xs:annotation>
<xs:documentation>
A real number expressed using a whole and optional fractional part
separated by a period, with optional exponential notation.
No leading '+' is allowed. Leading zeros are not allowed except
for the integer 0 itself or numbers less than 1 (e.g., 0.5).
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:double">
<xs:pattern value="-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="description" type="xs:string" use="required"/>
<xs:attribute name="expected" use="required">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="valid"/>
<xs:enumeration value="invalid"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>

</xs:schema>
47 changes: 47 additions & 0 deletions test/decimal-type/json-invalid-cases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"$schema": "decimal-test.json",
"_comment": "Invalid decimal test cases for JSON validation. These values SHOULD FAIL JSON Schema validation or are invalid JSON syntax.",
"_note": "JSON does not allow: leading +, leading/trailing whitespace, .47 syntax, 123. syntax. These would be syntax errors or string values.",
"decimal-tests": {
"test-cases": [
{
"id": "json-placeholder",
"description": "Placeholder - see comments below for invalid cases that cannot be represented in JSON",
"expected": "valid",
"value": 0
}
]
},
"_invalid_cases_documentation": {
"leading_plus": {
"example": "+12.34",
"reason": "JSON syntax does not allow leading + on numbers. This would be a parse error.",
"expected": "invalid"
},
"leading_zeros": {
"example": "01.23",
"reason": "JSON syntax does not allow leading zeros on numbers (except 0 itself). This would be a parse error.",
"expected": "invalid"
},
"no_leading_digit": {
"example": ".47",
"reason": "JSON syntax requires a digit before the decimal point. This would be a parse error.",
"expected": "invalid"
},
"trailing_decimal": {
"example": "123.",
"reason": "JSON syntax requires digits after the decimal point. This would be a parse error.",
"expected": "invalid"
},
"leading_whitespace": {
"example": " 12.34",
"reason": "If represented as a string \" 12.34\", it would fail type: number validation.",
"expected": "invalid"
},
"trailing_whitespace": {
"example": "12.34 ",
"reason": "If represented as a string \"12.34 \", it would fail type: number validation.",
"expected": "invalid"
}
}
}
13 changes: 13 additions & 0 deletions test/decimal-type/json-test-string-value.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "decimal-test.json",
"decimal-tests": {
"test-cases": [
{
"id": "json-string-with-whitespace",
"description": "String value with whitespace should fail type: number",
"expected": "invalid",
"value": " 12.34 "
}
]
}
}
68 changes: 68 additions & 0 deletions test/decimal-type/json-valid-cases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"$schema": "decimal-test.json",
"_comment": "Valid decimal test cases for JSON validation. All values SHOULD pass JSON Schema validation with type: number",
"decimal-tests": {
"test-cases": [
{
"id": "json-int-positive",
"description": "Positive integer (e.g., 12)",
"expected": "valid",
"value": 12
},
{
"id": "json-int-negative",
"description": "Negative integer",
"expected": "valid",
"value": -42
},
{
"id": "json-int-zero",
"description": "Zero",
"expected": "valid",
"value": 0
},
{
"id": "json-dec-positive",
"description": "Positive decimal (e.g., 12.34)",
"expected": "valid",
"value": 12.34
},
{
"id": "json-dec-negative",
"description": "Negative decimal",
"expected": "valid",
"value": -12.34
},
{
"id": "json-dec-small",
"description": "Small decimal",
"expected": "valid",
"value": 0.001
},
{
"id": "json-exp-lower",
"description": "Exponential notation lowercase (e.g., 1e3) - Valid in JSON",
"expected": "valid",
"value": 1e3
},
{
"id": "json-exp-upper-plus",
"description": "Exponential notation uppercase with plus (e.g., 1E+4) - Valid in JSON",
"expected": "valid",
"value": 1E+4
},
{
"id": "json-exp-negative",
"description": "Exponential notation negative (e.g., -2.5e-10) - Valid in JSON",
"expected": "valid",
"value": -2.5e-10
},
{
"id": "json-decimal-no-leading-zero",
"description": "Decimal without unnecessary leading zeros (1.23 is valid; 01.23 is invalid JSON syntax)",
"expected": "valid",
"value": 1.23
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
]
}
}
26 changes: 26 additions & 0 deletions test/decimal-type/xml-invalid-cases.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Invalid decimal test cases for XML validation.
Each test-case is in a separate file because invalid values cause validation to fail.
This file documents all invalid cases and their expected behavior.

Test files:
- xml-test-leading-plus.xml: +12.34 (INVALID - leading + not allowed)
- xml-test-leading-zero.xml: 01.23 (INVALID - leading zeros not allowed)
- xml-test-no-leading-digit.xml: .47 (INVALID - must have digit before decimal)
- xml-test-trailing-decimal.xml: 123. (INVALID - must have digit after decimal)
- xml-test-leading-whitespace.xml: " 12.34" (VALID due to xs:double whitespace collapse)

Note: Leading/trailing whitespace passes validation because xs:double
applies whitespace normalization before pattern matching.
-->
<decimal-tests xmlns="http://csrc.nist.gov/ns/metaschema/test/decimal"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/metaschema/test/decimal decimal-test.xsd">

<!-- This is a placeholder. See individual xml-test-*.xml files for actual invalid cases. -->
<test-case id="placeholder" description="Placeholder - see individual test files" expected="valid">
<value>0</value>
</test-case>

</decimal-tests>
8 changes: 8 additions & 0 deletions test/decimal-type/xml-test-leading-plus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<decimal-tests xmlns="http://csrc.nist.gov/ns/metaschema/test/decimal"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/metaschema/test/decimal decimal-test.xsd">
<test-case id="xml-leading-plus" description="Leading plus sign (e.g., +12.34)" expected="invalid">
<value>+12.34</value>
</test-case>
</decimal-tests>
8 changes: 8 additions & 0 deletions test/decimal-type/xml-test-leading-whitespace.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<decimal-tests xmlns="http://csrc.nist.gov/ns/metaschema/test/decimal"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/metaschema/test/decimal decimal-test.xsd">
<test-case id="xml-leading-whitespace" description="Leading whitespace (passes due to xs:double whitespace collapse)" expected="valid">
<value> 12.34</value>
</test-case>
</decimal-tests>
8 changes: 8 additions & 0 deletions test/decimal-type/xml-test-leading-zero.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<decimal-tests xmlns="http://csrc.nist.gov/ns/metaschema/test/decimal"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://csrc.nist.gov/ns/metaschema/test/decimal decimal-test.xsd">
<test-case id="xml-leading-zero" description="Leading zeros (e.g., 01.23)" expected="invalid">
<value>01.23</value>
</test-case>
</decimal-tests>
Loading