├── test
├── utf16.xml
├── issue3.xml
├── invalid.xml
├── issue3.json
├── version1-1.xml
├── xml-rpc.xml
├── issue4.xml
├── issue9.xsd
├── control.invalid.xml
├── entity.invalid.xml
├── hexentity.invalid.xml
├── dtd.xml
├── entities.pull.xml
├── soap.xml
├── address.json
├── issue12.xsd
├── coerceTypes.xml
├── issue4.json
├── valueProperty.xml
├── issue12b.xsd
├── address.xml
├── rss.xml
├── badge.svg
├── bookstore.json
├── bookstore.xml
├── example.xhtml
├── addressSchema.xsd
├── shiporderSchema.xsd
├── word.xml
├── xbrl.xml
├── sample.wsdl
├── purchaseorder.xsd
├── structure.invalid.xml
├── pc_hd_abr_v2_dash_master.coerceTypes.noap.mpd
├── web.config
├── c4atom_noap.coerceTypes.xml
├── atomSchema.xsd
└── mpd-dash.xsd
├── out
├── fragment1.xml
├── bookstore.jpath
├── issue3.xml
├── issue3.json
├── soap.json
├── issue4.xml
├── address.xml
├── coerceTypes.json
├── issue12.json
├── issue4.json
├── issue12b.json
├── address.json
├── issue9.json
├── rss.json
├── bookstore.json
├── bookstore.xml
├── addressSchema.json
├── valueProperty.json
├── example.json
├── badge.json
├── shiporderSchema.json
├── word.json
├── sample.json
├── purchaseorder.json
├── pc_hd_abr_v2_dash_master.coerceTypes.noap.json
├── c4atom_noap.coerceTypes.json
└── atomSchema.json
├── .editorconfig
├── common.js
├── examples
├── fragment.js
├── pushparser.js
├── pullparser.js
├── jsont.js
├── xml2xml.js
└── jpath.js
├── .github
└── workflows
│ └── ci.yaml
├── cli
├── xml2json.js
├── json2xml.js
└── xsd2json.js
├── .gitignore
├── .npmignore
├── package.json
├── json2xml.js
├── LICENSE
├── jsont.js
├── README.md
├── xmlWrite.js
├── xml2json.js
├── jpath.js
├── testRunner.js
└── jgeXml.js
/test/utf16.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mermade/jgeXml/HEAD/test/utf16.xml
--------------------------------------------------------------------------------
/out/fragment1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | baz
5 |
--------------------------------------------------------------------------------
/out/bookstore.jpath:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "query": "$.store.book[2].price",
4 | "fetch": "store.book[2].price",
5 | "expected": "8.99"
6 | }
7 | ]
--------------------------------------------------------------------------------
/test/issue3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | B1
5 |
6 | B2
7 |
--------------------------------------------------------------------------------
/test/invalid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Ref=some here
5 |
6 |
7 |
--------------------------------------------------------------------------------
/out/issue3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | B1
6 | B2
7 |
--------------------------------------------------------------------------------
/out/issue3.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "header": [
4 | "H1",
5 | "H2"
6 | ],
7 | "body": [
8 | "B1",
9 | "B2"
10 | ]
11 | }
12 | }
--------------------------------------------------------------------------------
/test/issue3.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": {
3 | "header": [
4 | "H1",
5 | "H2"
6 | ],
7 | "body": [
8 | "B1",
9 | "B2"
10 | ]
11 | }
12 | }
--------------------------------------------------------------------------------
/test/version1-1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 1
6 |
7 |
--------------------------------------------------------------------------------
/test/xml-rpc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | examples.getStateName
4 |
5 |
6 | 40
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | indent_style = space
6 | indent_size = 4
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/test/issue4.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is Raphael's 'Foligno' Madonna, painted in
5 | 1511-1512.
6 |
--------------------------------------------------------------------------------
/common.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(String.prototype,'replaceAll',{
4 | value: function(search, replacement) {
5 | var target = this;
6 | return target.split(search).join(replacement);
7 | },
8 | enumerable: false}
9 | );
10 |
11 |
--------------------------------------------------------------------------------
/test/issue9.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/out/soap.json:
--------------------------------------------------------------------------------
1 | {
2 | "soap:Envelope": {
3 | "@xmlns:soap": "http://www.w3.org/2003/05/soap-envelope",
4 | "soap:Header": {},
5 | "soap:Body": {
6 | "m:GetStockPrice": {
7 | "@xmlns:m": "http://www.example.org/stock/Surya",
8 | "m:StockName": "IBM"
9 | }
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/test/control.invalid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | dataval1
5 | dataval2
6 |
7 |
8 | 3
9 | dataval4
10 |
11 |
--------------------------------------------------------------------------------
/test/entity.invalid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | dataval1
5 | dataval2
6 |
7 |
8 | 3
9 | dataval4
10 |
11 |
--------------------------------------------------------------------------------
/test/hexentity.invalid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | dataval1
5 | dataval2
6 |
7 |
8 | 3
9 | dataval4
10 |
11 |
--------------------------------------------------------------------------------
/test/dtd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
9 |
10 |
11 |
12 | ]>
13 |
14 | Hello World.
--------------------------------------------------------------------------------
/test/entities.pull.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | dataval1
5 | dataval 2
6 |
7 |
8 | 3
9 | dataval4
10 |
11 |
12 |
--------------------------------------------------------------------------------
/test/soap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | IBM
8 |
9 |
10 |
--------------------------------------------------------------------------------
/out/issue4.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <#text>This is Raphael's 'Foligno' Madonna, painted in#text>
6 | <#text>-#text>
7 | <#text>.#text>
8 | 1511
9 | 1512
10 |
11 |
--------------------------------------------------------------------------------
/test/address.json:
--------------------------------------------------------------------------------
1 | {
2 | "Address": {
3 | "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
4 | "@xsi:noNamespaceSchemaLocation": "SimpleAddress.xsd",
5 | "Recipient": "Mr. Walter C. Brown",
6 | "House": "49",
7 | "Street": "Featherstone Street",
8 | "Town": "LONDON",
9 | "PostCode": "EC1Y 8SY",
10 | "Country": "UK"
11 | }
12 | }
--------------------------------------------------------------------------------
/test/issue12.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/out/address.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Mr. Walter C. Brown
4 | 49
5 | Featherstone Street
6 | LONDON
7 | EC1Y 8SY
8 | UK
9 |
--------------------------------------------------------------------------------
/out/coerceTypes.json:
--------------------------------------------------------------------------------
1 | {
2 | "Tests": {
3 | "quoting": [
4 | {
5 | "data": "string"
6 | },
7 | {
8 | "data": 1
9 | },
10 | {
11 | "data": 2
12 | },
13 | {
14 | "data": 2.5
15 | },
16 | {
17 | "data": true
18 | },
19 | {
20 | "data": {}
21 | }
22 | ]
23 | }
24 | }
--------------------------------------------------------------------------------
/test/coerceTypes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | string
5 |
6 |
7 | 1
8 |
9 |
10 | 2
11 |
12 |
13 | 2.5
14 |
15 |
16 | true
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/out/issue12.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/issue12.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "type": "object",
5 | "properties": {
6 | "DateType1Code": {
7 | "type": "string",
8 | "enum": [
9 | "UKWN"
10 | ]
11 | }
12 | },
13 | "required": [
14 | "Address",
15 | "DateType1Code"
16 | ],
17 | "additionalProperties": false
18 | }
19 |
--------------------------------------------------------------------------------
/out/issue4.json:
--------------------------------------------------------------------------------
1 | {
2 | "painting": {
3 | "img": {
4 | "@src": "madonna.jpg",
5 | "@alt": "Foligno Madonna, by Raphael"
6 | },
7 | "caption": {
8 | "#text": [
9 | "This is Raphael's 'Foligno' Madonna, painted in",
10 | "-",
11 | "."
12 | ],
13 | "date": [
14 | "1511",
15 | "1512"
16 | ]
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/test/issue4.json:
--------------------------------------------------------------------------------
1 | {
2 | "painting": {
3 | "img": {
4 | "@src": "madonna.jpg",
5 | "@alt": "Foligno Madonna, by Raphael"
6 | },
7 | "caption": {
8 | "#text": [
9 | "This is Raphael's 'Foligno' Madonna, painted in",
10 | "-",
11 | "."
12 | ],
13 | "date": [
14 | "1511",
15 | "1512"
16 | ]
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/test/valueProperty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | sibling1
5 | sibling2
6 |
7 |
8 | sibling3
9 | sibling4
10 |
11 |
--------------------------------------------------------------------------------
/examples/fragment.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var xw = require('../xmlWrite');
4 |
5 | xw.startFragment(2);
6 | xw.docType('fubar');
7 | xw.startElement('foo');
8 | xw.processingInstruction('nitfol xyzzy');
9 | xw.startElement('bar');
10 | xw.comment('potrzebie');
11 | xw.content('baz');
12 | xw.cdata('snafu');
13 | xw.endElement('bar');
14 | xw.endElement('foo');
15 |
16 | console.log(xw.endFragment());
17 |
--------------------------------------------------------------------------------
/test/issue12b.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/out/issue12b.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/issue12b.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "type": "object",
5 | "properties": {
6 | "DateType1Code": {
7 | "type": "string",
8 | "enum": [
9 | "UKWN",
10 | "VAL2"
11 | ]
12 | }
13 | },
14 | "required": [
15 | "Address",
16 | "DateType1Code"
17 | ],
18 | "additionalProperties": false
19 | }
20 |
--------------------------------------------------------------------------------
/out/address.json:
--------------------------------------------------------------------------------
1 | {
2 | "Address": {
3 | "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
4 | "@xsi:noNamespaceSchemaLocation": "SimpleAddress.xsd",
5 | "Recipient": "Mr. Walter C. Brown",
6 | "House": {
7 | "#text": [
8 | "49",
9 | "A"
10 | ]
11 | },
12 | "Street": "Featherstone Street",
13 | "Town": "LONDON",
14 | "PostCode": "EC1Y 8SY",
15 | "#text": "Customer123",
16 | "Country": "UK"
17 | }
18 | }
--------------------------------------------------------------------------------
/out/issue9.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/issue9.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "type": "object",
5 | "properties": {
6 | "test": {
7 | "properties": {
8 | "id": {
9 | "type": "string",
10 | "enum": [
11 | "123"
12 | ]
13 | }
14 | },
15 | "additionalProperties": false,
16 | "type": "object"
17 | }
18 | },
19 | "required": [
20 | "test"
21 | ],
22 | "additionalProperties": false
23 | }
24 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yaml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | push:
5 | branches: [ 'main' ]
6 | pull_request:
7 | branches: [ 'main' ]
8 |
9 | jobs:
10 | test:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [12, 14, 16]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up node
20 | uses: actions/setup-node@v1
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 |
24 | - run: npm i
25 | # - run: npm run lint
26 | - run: npm run test
27 |
28 |
--------------------------------------------------------------------------------
/test/address.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | Mr. Walter C. Brown
8 | 49A
9 | Featherstone Street
10 | LONDON
11 | EC1Y 8SY
12 |
13 | UK
14 |
--------------------------------------------------------------------------------
/test/rss.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Example Channel
5 | http://example.com/
6 | My example channel
7 | -
8 | News for September the Second
9 | http://example.com/2002/09/01
10 | other things happened today
11 |
12 | -
13 | News for September the First
14 | http://example.com/2002/09/02
15 |
16 |
17 |
--------------------------------------------------------------------------------
/out/rss.json:
--------------------------------------------------------------------------------
1 | {
2 | "rss": {
3 | "@version": "2.0",
4 | "channel": {
5 | "title": "Example Channel",
6 | "link": "http://example.com/",
7 | "description": "My example channel",
8 | "item": [
9 | {
10 | "title": "News for September the Second",
11 | "link": "http://example.com/2002/09/01",
12 | "description": "other things happened today"
13 | },
14 | {
15 | "title": "News for September the First",
16 | "link": "http://example.com/2002/09/02"
17 | }
18 | ]
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/cli/xml2json.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | var fs = require('fs');
5 | var x2j = require('../xml2json');
6 |
7 | var filename = process.argv[2];
8 | if (!filename) {
9 | console.warn('Usage: xml2json {infile}');
10 | process.exit(1);
11 | }
12 | var valueProperty = false;
13 | var coerceTypes = false;
14 |
15 | if (process.argv.length>3) {
16 | valueProperty = (process.argv[3] != '0');
17 | }
18 | if (process.argv.length>4) {
19 | coerceTypes = (process.argv[4] != '0');
20 | }
21 |
22 | var xml = fs.readFileSync(filename,'utf8');
23 |
24 | var obj = x2j.xml2json(xml,{"attributePrefix": "@","valueProperty": valueProperty, "coerceTypes": coerceTypes});
25 | console.log(JSON.stringify(obj,null,2));
26 |
--------------------------------------------------------------------------------
/cli/json2xml.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | var fs = require('fs');
5 | var j2x = require('../json2xml');
6 |
7 | var filename = process.argv[2];
8 | if (!filename) {
9 | console.warn('Usage: json2xml {infile}');
10 | process.exit(1);
11 | }
12 | var indent = 2;
13 | var indentStr = ' ';
14 |
15 | if (process.argv.length>3) {
16 | indent = 1;
17 | indentStr = '\t';
18 | }
19 |
20 | var json = fs.readFileSync(filename,'utf8');
21 |
22 | var obj = {};
23 | try {
24 | obj = JSON.parse(json);
25 | }
26 | catch (err) {
27 | console.error('That is not valid JSON');
28 | console.error(err);
29 | process.exit(1);
30 | }
31 |
32 | var xml = j2x.getXml(obj,'@','',indent,indentStr,false);
33 | console.log(xml);
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | package-lock.json
2 | test/nitro-schema.xsd
3 | out/nitro-schema.json
4 |
5 | in/
6 | .vscode/
7 |
8 | # Logs
9 | logs
10 | *.log
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 |
17 | # Directory for instrumented libs generated by jscoverage/JSCover
18 | lib-cov
19 |
20 | # Coverage directory used by tools like istanbul
21 | coverage
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # node-waf configuration
27 | .lock-wscript
28 |
29 | # Compiled binary addons (http://nodejs.org/api/addons.html)
30 | build/Release
31 |
32 | # Dependency directory
33 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
34 | node_modules
35 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test/
2 | in/
3 | out/
4 | .vscode/
5 | old/
6 | musicxml/
7 | xmlbible/
8 | doc/
9 | ideas/
10 | temp/
11 |
12 | # Logs
13 | logs
14 | *.log
15 |
16 | # Runtime data
17 | pids
18 | *.pid
19 | *.seed
20 |
21 | # Directory for instrumented libs generated by jscoverage/JSCover
22 | lib-cov
23 |
24 | # Coverage directory used by tools like istanbul
25 | coverage
26 |
27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
28 | .grunt
29 |
30 | # node-waf configuration
31 | .lock-wscript
32 |
33 | # Compiled binary addons (http://nodejs.org/api/addons.html)
34 | build/Release
35 |
36 | # Dependency directory
37 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
38 | node_modules
39 |
--------------------------------------------------------------------------------
/examples/pushparser.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var jgeXml = require('../jgeXml.js');
5 |
6 | var filename = process.argv[2];
7 | if (!filename) {
8 | console.warn('Usage: pushparser {infile} [encoding]');
9 | process.exit(1);
10 | }
11 | var encoding = 'utf8';
12 | if (process.argv.length>3) encoding = process.argv[3];
13 |
14 | var xml = fs.readFileSync(filename,encoding);
15 | console.log(xml);
16 | console.log();
17 |
18 | var depth = 0;
19 |
20 | var result = jgeXml.parse(xml,function(state,token){
21 | if (state == jgeXml.sElement) {
22 | depth++;
23 | }
24 | else if (state == jgeXml.sEndElement) {
25 | depth--;
26 | }
27 | console.log(jgeXml.getStateName(state)+' '+depth+' "'+token+'"');
28 | });
29 | console.log(result);
30 | if (!result) process.exitCode = 1;
31 |
--------------------------------------------------------------------------------
/test/badge.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/bookstore.json:
--------------------------------------------------------------------------------
1 | { "store": {
2 | "book": [
3 | { "category": "reference",
4 | "author": "Nigel Rees",
5 | "title": "Sayings of the Century",
6 | "price": 8.95
7 | },
8 | { "category": "fiction",
9 | "author": "Evelyn Waugh",
10 | "title": "Sword of Honour",
11 | "price": 12.99
12 | },
13 | { "category": "fiction",
14 | "author": "Herman Melville",
15 | "title": "Moby Dick",
16 | "isbn": "0-553-21311-3",
17 | "price": 8.99
18 | },
19 | { "category": "fiction",
20 | "author": "J. R. R. Tolkien",
21 | "title": "The Lord of the Rings",
22 | "isbn": "0-395-19395-8",
23 | "price": 22.99
24 | }
25 | ],
26 | "bicycle": {
27 | "color": "red",
28 | "price": 19.95
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/bookstore.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | reference
5 | Nigel Rees
6 | Sayings of the Century
7 | 8.95
8 |
9 |
10 | fiction
11 | Evelyn Waugh
12 | Sword of Honour
13 | 12.99
14 |
15 |
16 | fiction
17 | Herman Melville
18 | Moby Dick
19 | 0-553-21311-3
20 | 8.99
21 |
22 |
23 | fiction
24 | J. R. R. Tolkien
25 | The Lord of the Rings
26 | 0-395-19395-8
27 | 22.99
28 |
29 |
30 | red
31 | 19.95
32 |
33 |
--------------------------------------------------------------------------------
/out/bookstore.json:
--------------------------------------------------------------------------------
1 | {
2 | "store": {
3 | "book": [
4 | {
5 | "category": "reference",
6 | "author": "Nigel Rees",
7 | "title": "Sayings of the Century",
8 | "price": "8.95"
9 | },
10 | {
11 | "category": "fiction",
12 | "author": "Evelyn Waugh",
13 | "title": "Sword of Honour",
14 | "price": "12.99"
15 | },
16 | {
17 | "category": "fiction",
18 | "author": "Herman Melville",
19 | "title": "Moby Dick",
20 | "isbn": "0-553-21311-3",
21 | "price": "8.99"
22 | },
23 | {
24 | "category": "fiction",
25 | "author": "J. R. R. Tolkien",
26 | "title": "The Lord of the Rings",
27 | "isbn": "0-395-19395-8",
28 | "price": "22.99"
29 | }
30 | ],
31 | "bicycle": {
32 | "color": "red",
33 | "price": "19.95"
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/out/bookstore.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | reference
5 | Nigel Rees
6 | Sayings of the Century
7 | 8.95
8 |
9 |
10 | fiction
11 | Evelyn Waugh
12 | Sword of Honour
13 | 12.99
14 |
15 |
16 | fiction
17 | Herman Melville
18 | Moby Dick
19 | 0-553-21311-3
20 | 8.99
21 |
22 |
23 | fiction
24 | J. R. R. Tolkien
25 | The Lord of the Rings
26 | 0-395-19395-8
27 | 22.99
28 |
29 |
30 | red
31 | 19.95
32 |
33 |
--------------------------------------------------------------------------------
/test/example.xhtml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | XHTML 1.0 Strict Example
7 |
10 |
11 |
12 | This is an example of an
13 | XHTML 1.0 Strict document.
14 | 
17 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/examples/pullparser.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var jgeXml = require('../jgeXml.js');
5 |
6 | var filename = process.argv[2];
7 | if (!filename) {
8 | console.warn('Usage: pullparser {infile} [encoding]');
9 | process.exit(1);
10 | }
11 | var encoding = 'utf8';
12 | if (process.argv.length>3) encoding = process.argv[3];
13 |
14 | var xml = fs.readFileSync(filename,encoding);
15 | console.log(xml);
16 | console.log();
17 |
18 | var context = {};
19 | var depth = 0;
20 |
21 | while (!context.state || context.state != jgeXml.sEndDocument) {
22 | context = jgeXml.parse(xml,null,context);
23 | if (context.state == jgeXml.sElement) {
24 | depth++;
25 | }
26 | else if (context.state == jgeXml.sEndElement) {
27 | depth--;
28 | }
29 | console.log(jgeXml.getStateName(context.state)+' '+context.position+' '+depth+' '+context.depth+' "'+context.token+'"');
30 | }
31 | console.log(context.wellFormed);
32 | if (!context.wellFormed) process.exitCode = 1;
33 |
--------------------------------------------------------------------------------
/cli/xsd2json.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | var fs = require('fs');
5 | var x2j = require('../xml2json');
6 | var xsd = require('../xsd2json');
7 |
8 | var filename = process.argv[2];
9 | if (!filename) {
10 | console.warn('Usage: xsd2json {infile} [{outfile}]');
11 | process.exit(1);
12 | }
13 | var valueProperty = false;
14 |
15 | var xml = fs.readFileSync(filename,'utf8');
16 |
17 | try {
18 | var obj = x2j.xml2json(xml,{"attributePrefix": "@","valueProperty": valueProperty, "coerceTypes": false});
19 | }
20 | catch (err) {
21 | console.error('That is not valid JSON');
22 | console.error(err);
23 | console.log(x2j.getString());
24 | process.exit(1);
25 | }
26 |
27 | var laxUris = (filename.indexOf('.lax')>=0);
28 | var json = xsd.getJsonSchema(obj,filename,'',laxUris,'xs:');
29 |
30 | if (process.argv.length>3) {
31 | var outfile = process.argv[3];
32 | fs.writeFileSync(outfile,JSON.stringify(json,null,2),'utf8');
33 | }
34 | else {
35 | console.log(JSON.stringify(json,null,2));
36 | }
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jgexml",
3 | "version": "0.4.3",
4 | "description": "The Just-Good-Enough XML Toolkit",
5 | "main": "jgeXml.js",
6 | "bin": {
7 | "xml2json": "./cli/xml2json.js",
8 | "json2xml": "./cli/json2xml.js",
9 | "xsd2json": "./cli/xsd2json.js"
10 | },
11 | "scripts": {
12 | "test": "node testRunner",
13 | "cover": "npx istanbul cover testRunner.js"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/Mermade/jgeXml.git"
18 | },
19 | "keywords": [
20 | "xml",
21 | "javascript",
22 | "json",
23 | "jsonpath",
24 | "jsont",
25 | "parser",
26 | "pullparser",
27 | "pullparsing",
28 | "pushparser",
29 | "pushparsing",
30 | "sax",
31 | "stax",
32 | "schema",
33 | "xsd"
34 | ],
35 | "author": "Mike Ralphson",
36 | "license": "BSD-3-Clause",
37 | "bugs": {
38 | "url": "https://github.com/Mermade/jgeXml/issues"
39 | },
40 | "homepage": "https://github.com/Mermade/jgeXml#readme"
41 | }
42 |
--------------------------------------------------------------------------------
/test/addressSchema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/out/addressSchema.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/addressSchema.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "type": "object",
5 | "properties": {
6 | "Address": {
7 | "properties": {
8 | "Recipient": {
9 | "type": "string"
10 | },
11 | "House": {
12 | "type": "string"
13 | },
14 | "Street": {
15 | "type": "string"
16 | },
17 | "Town": {
18 | "type": "string"
19 | },
20 | "County": {
21 | "type": "string"
22 | },
23 | "PostCode": {
24 | "type": "string"
25 | },
26 | "Country": {
27 | "type": "string",
28 | "enum": [
29 | "IN",
30 | "DE",
31 | "ES",
32 | "UK",
33 | "US"
34 | ]
35 | }
36 | },
37 | "required": [
38 | "Recipient",
39 | "House",
40 | "Street",
41 | "Town",
42 | "PostCode"
43 | ],
44 | "additionalProperties": false
45 | }
46 | },
47 | "required": [
48 | "Address"
49 | ],
50 | "additionalProperties": false
51 | }
52 |
--------------------------------------------------------------------------------
/out/valueProperty.json:
--------------------------------------------------------------------------------
1 | {
2 | "test": [
3 | {
4 | "element": [
5 | {
6 | "@name": "parent1",
7 | "elementInner": [
8 | {
9 | "@name": "child1",
10 | "#text": [
11 | {
12 | "#value": "sibling1"
13 | }
14 | ]
15 | },
16 | {
17 | "@name": "child2",
18 | "#text": [
19 | {
20 | "#value": "sibling2"
21 | }
22 | ]
23 | }
24 | ]
25 | },
26 | {
27 | "@name": "parent2",
28 | "elementInner": [
29 | {
30 | "@name": "child1",
31 | "#text": [
32 | {
33 | "#value": "sibling3"
34 | }
35 | ]
36 | },
37 | {
38 | "@name": "child2",
39 | "#text": [
40 | {
41 | "#value": "sibling4"
42 | }
43 | ]
44 | }
45 | ]
46 | }
47 | ]
48 | }
49 | ]
50 | }
--------------------------------------------------------------------------------
/examples/jsont.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var jsont = require('../jsont');
4 |
5 | function run(obj,rules) {
6 | console.log();
7 | console.log(obj);
8 | console.log('+');
9 | console.log(rules);
10 | console.log('=');
11 | console.log(jsont.transform(obj,rules));
12 | }
13 |
14 | // see http://goessner.net/articles/jsont/
15 |
16 | var obj = { "link": {"uri":"http://company.com", "title":"company homepage" }};
17 | var rules = { "link": "{link.title}" };
18 | run(obj,rules);
19 |
20 | obj = { "line": { "p1": {"x":2, "y":3},
21 | "p2": {"x":4, "y":5} }};
22 | rules = { "self": "",
23 | "line": "" };
25 | run(obj,rules);
26 |
27 | obj = ["red", "green", "blue"]
28 | rules = {"self": "",
29 | "self[*]": " {$}\n"};
30 | run(obj,rules);
31 |
32 | obj = { "color": "blue",
33 | "closed": true,
34 | "points": [[10,10],[20,10],[20,20],[10,20]] };
35 | rules = { "self": "",
37 | "closed": function(x){return x ? "polygon" : "polyline";},
38 | "points[*][*]": "{$} " };
39 | run(obj,rules);
40 |
--------------------------------------------------------------------------------
/out/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "html": {
3 | "@xmlns": "http://www.w3.org/1999/xhtml",
4 | "@xml:lang": "en",
5 | "head": {
6 | "title": "XHTML 1.0 Strict Example",
7 | "script": {
8 | "@type": "application/javascript",
9 | "#text": "function loadpdf() {document.getElementById(\"pdf-object\").src=\"http://www.w3.org/TR/xhtml1/xhtml1.pdf\";}"
10 | }
11 | },
12 | "body": {
13 | "@onload": "loadpdf()",
14 | "p": {
15 | "#text": [
16 | "This is an example of an",
17 | "1.0 Strict document."
18 | ],
19 | "abbr": {
20 | "@title": "Extensible HyperText Markup Language",
21 | "#text": "XHTML"
22 | },
23 | "br": [
24 | {},
25 | {}
26 | ],
27 | "img": {
28 | "@id": "validation-icon",
29 | "@src": "http://www.w3.org/Icons/valid-xhtml10",
30 | "@alt": "Valid XHTML 1.0 Strict"
31 | },
32 | "object": {
33 | "@id": "pdf-object",
34 | "@type": "application/pdf",
35 | "@data": "http://www.w3.org/TR/xhtml1/xhtml1.pdf",
36 | "@width": "100%",
37 | "@height": "500"
38 | }
39 | }
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/test/shiporderSchema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/json2xml.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var xmlWrite = require('./xmlWrite');
4 |
5 | function traverse(obj,parent,attributePrefix) {
6 |
7 | var result = [];
8 |
9 | var array = Array.isArray(obj);
10 | for (var key in obj) {
11 | // skip loop if the property is from prototype
12 | if (!obj.hasOwnProperty(key)) continue;
13 |
14 | var propArray = Array.isArray(obj[key]);
15 | var output = array ? parent : key;
16 |
17 | if (typeof obj[key] !== 'object'){
18 | if (key.indexOf(attributePrefix) === 0) {
19 | xmlWrite.attribute(key.substring(1),obj[key]);
20 | }
21 | else {
22 | xmlWrite.startElement(output);
23 | xmlWrite.content(obj[key]);
24 | xmlWrite.endElement(output);
25 | }
26 | }
27 | else {
28 | if (!propArray) {
29 | xmlWrite.startElement(output);
30 | }
31 | traverse(obj[key],output,attributePrefix);
32 | if (!propArray) {
33 | xmlWrite.endElement(output);
34 | }
35 | }
36 | }
37 | return result;
38 | }
39 |
40 | module.exports = {
41 | // TODO convert this to an options object
42 | getXml : function(obj,attrPrefix,standalone,indent,indentStr,fragment) {
43 | var attributePrefix = (attrPrefix ? attrPrefix : '@');
44 | if (fragment) {
45 | xmlWrite.startFragment(indent,indentStr);
46 | }
47 | else {
48 | xmlWrite.startDocument('UTF-8',standalone,indent,indentStr);
49 | }
50 | traverse(obj,'',attributePrefix);
51 | return xmlWrite.endDocument();
52 | }
53 | };
--------------------------------------------------------------------------------
/examples/xml2xml.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var jgeXml = require('../jgeXml.js');
5 | var xmlWrite = require('../xmlWrite.js');
6 |
7 | function x2x(xml) {
8 | var attributeName = '';
9 |
10 | jgeXml.parse(xml,function(state,token){
11 |
12 | if (state == jgeXml.sDeclaration) {
13 | xmlWrite.startDocument('UTF-8','',2);
14 | }
15 | else if (state == jgeXml.sComment) {
16 | xmlWrite.comment(token);
17 | }
18 | else if (state == jgeXml.sProcessingInstruction) {
19 | xmlWrite.processingInstruction(token);
20 | }
21 | else if (state == jgeXml.sCData) {
22 | xmlWrite.cdata(token);
23 | }
24 | else if (state == jgeXml.sContent) {
25 | xmlWrite.content(token);
26 | }
27 | else if (state == jgeXml.sEndElement) {
28 | xmlWrite.endElement(token);
29 | }
30 | else if (state == jgeXml.sAttribute) {
31 | attributeName = token;
32 | }
33 | else if (state == jgeXml.sValue) {
34 | xmlWrite.attribute(attributeName,token);
35 | }
36 | else if (state == jgeXml.sElement) {
37 | xmlWrite.startElement(token);
38 | }
39 | });
40 | return xmlWrite.endDocument();
41 | }
42 |
43 | var filename = process.argv[2];
44 | if (!filename) {
45 | console.warn('Usage: xml2xml {infile}');
46 | process.exit(1);
47 | }
48 |
49 | var xml = fs.readFileSync(filename,'utf8');
50 |
51 | var s1 = x2x(xml); // normalise declaration, spacing and empty elements etc
52 | var s2 = x2x(s1); // compare
53 | var same = (s1 == s2);
54 | if (!same) {
55 | console.warn(s1);
56 | process.exitCode = 1;
57 | }
58 | console.log(s2);
59 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Mike Ralphson
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of jgeXml nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
29 |
--------------------------------------------------------------------------------
/test/word.xml:
--------------------------------------------------------------------------------
1 |
2 | Hello, world.
--------------------------------------------------------------------------------
/jsont.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const jpath = require('./jpath');
4 |
5 | function replaceAll(s, from, to) {
6 | return s.split(from).join(to);
7 | }
8 |
9 | function transform(obj,rules) {
10 | var objName = '$';
11 | var isArray = false;
12 |
13 | for (var n in obj) {
14 | objName = n;
15 | break;
16 | }
17 |
18 | var arrRules = [];
19 |
20 | for (var r in rules) {
21 | var rule = {};
22 | rule.rule = rules[r];
23 | rule.ruleName = r;
24 | rule.processed = false;
25 | arrRules.push(rule);
26 | }
27 |
28 | for (var r=arrRules.length-1;r>=0;r--) {
29 | var inner = arrRules[r].rule;
30 |
31 | if (arrRules[r].ruleName.indexOf('[*]') > 0) {
32 | isArray = true;
33 | }
34 |
35 | for (var o in obj) {
36 | var newObjName = objName;
37 | if (isArray) {
38 | newObjName = o;
39 | }
40 | var elements;
41 | if (typeof inner === 'function') {
42 | if (o == arrRules[r].ruleName) {
43 | elements = [inner(obj[arrRules[r].ruleName])];
44 | }
45 | else {
46 | elements = [];
47 | }
48 | }
49 | else {
50 | elements = inner.split(/[\{\}]+/);
51 | }
52 |
53 | for (var i=1;i0) {
68 | obj[newObjName] = elements.join('');
69 | }
70 | if (!isArray) continue;
71 | }
72 | arrRules[r].processed = true;
73 | }
74 | if (Array.isArray(obj)) return obj[0]
75 | else return obj[objName];
76 | }
77 |
78 | module.exports = {
79 | transform : transform
80 | };
81 |
--------------------------------------------------------------------------------
/out/badge.json:
--------------------------------------------------------------------------------
1 | {
2 | "svg": {
3 | "@xmlns": "http://www.w3.org/2000/svg",
4 | "@width": "121",
5 | "@height": "20",
6 | "linearGradient": {
7 | "@id": "b",
8 | "@x2": "0",
9 | "@y2": "100%",
10 | "stop": [
11 | {
12 | "@offset": "0",
13 | "@stop-color": "#bbb",
14 | "@stop-opacity": ".1"
15 | },
16 | {
17 | "@offset": "1",
18 | "@stop-opacity": ".1"
19 | }
20 | ]
21 | },
22 | "mask": {
23 | "@id": "a",
24 | "rect": {
25 | "@width": "121",
26 | "@height": "20",
27 | "@rx": "3",
28 | "@fill": "#fff"
29 | }
30 | },
31 | "g": [
32 | {
33 | "@mask": "url(#a)",
34 | "path": [
35 | {
36 | "@fill": "#555",
37 | "@d": "M0 0h87v20H0z"
38 | },
39 | {
40 | "@fill": "#4c1",
41 | "@d": "M87 0h34v20H87z"
42 | },
43 | {
44 | "@fill": "url(#b)",
45 | "@d": "M0 0h121v20H0z"
46 | }
47 | ]
48 | },
49 | {
50 | "@fill": "#fff",
51 | "@text-anchor": "middle",
52 | "@font-family": "DejaVu Sans,Verdana,Geneva,sans-serif",
53 | "@font-size": "11",
54 | "text": [
55 | {
56 | "@x": "43.5",
57 | "@y": "15",
58 | "@fill": "#010101",
59 | "@fill-opacity": ".3",
60 | "#text": "XML"
61 | },
62 | {
63 | "@x": "43.5",
64 | "@y": "14",
65 | "#text": "XML"
66 | },
67 | {
68 | "@x": "103",
69 | "@y": "15",
70 | "@fill": "#010101",
71 | "@fill-opacity": ".3",
72 | "#text": "VALID"
73 | },
74 | {
75 | "@x": "103",
76 | "@y": "14",
77 | "#text": "VALID"
78 | }
79 | ]
80 | }
81 | ]
82 | }
83 | }
--------------------------------------------------------------------------------
/test/xbrl.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 | 38679000000
13 | 35996000000
15 | 870000000
17 | ...
18 | 10430000000
20 |
21 |
22 | ACME
23 |
24 |
25 | 2004-01-01
26 |
27 |
28 |
29 |
30 | ACME
31 |
32 |
33 | 2004-12-31
34 |
35 |
36 |
37 |
38 | ACME
39 |
40 |
41 | 2004-01-01
42 | 2004-12-31
43 |
44 |
45 |
46 | iso4217:EUR
47 |
48 |
--------------------------------------------------------------------------------
/out/shiporderSchema.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/shiporderSchema.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "type": "object",
5 | "properties": {
6 | "shiporder": {
7 | "properties": {
8 | "orderperson": {
9 | "type": "string"
10 | },
11 | "shipto": {
12 | "type": "object",
13 | "properties": {
14 | "name": {
15 | "type": "string"
16 | },
17 | "address": {
18 | "type": "string"
19 | },
20 | "city": {
21 | "type": "string"
22 | },
23 | "country": {
24 | "type": "string"
25 | }
26 | },
27 | "required": [
28 | "name",
29 | "address",
30 | "city",
31 | "country"
32 | ],
33 | "additionalProperties": false
34 | },
35 | "item": {
36 | "type": "array",
37 | "minItems": 1,
38 | "items": {
39 | "type": "object",
40 | "properties": {
41 | "title": {
42 | "type": "string"
43 | },
44 | "note": {
45 | "type": "array",
46 | "items": {
47 | "type": "string"
48 | }
49 | },
50 | "quantity": {
51 | "type": "integer",
52 | "minimum": 1
53 | },
54 | "price": {
55 | "type": "number"
56 | }
57 | },
58 | "required": [
59 | "title",
60 | "quantity",
61 | "price"
62 | ],
63 | "additionalProperties": false
64 | }
65 | },
66 | "orderid": {
67 | "type": "string"
68 | },
69 | "invoiceid": {
70 | "type": "string"
71 | }
72 | },
73 | "required": [
74 | "orderperson",
75 | "shipto",
76 | "item",
77 | "orderid"
78 | ],
79 | "additionalProperties": false
80 | }
81 | },
82 | "required": [
83 | "shiporder"
84 | ],
85 | "additionalProperties": false
86 | }
--------------------------------------------------------------------------------
/test/sample.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | This is a sample WSDL 2.0 document.
10 |
11 |
12 |
13 |
14 |
17 |
18 | ...
19 | ...
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
54 |
55 |
--------------------------------------------------------------------------------
/out/word.json:
--------------------------------------------------------------------------------
1 | {
2 | "w:document": {
3 | "@xmlns:wpc": "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
4 | "@xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
5 | "@xmlns:o": "urn:schemas-microsoft-com:office:office",
6 | "@xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
7 | "@xmlns:m": "http://schemas.openxmlformats.org/officeDocument/2006/math",
8 | "@xmlns:v": "urn:schemas-microsoft-com:vml",
9 | "@xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
10 | "@xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
11 | "@xmlns:w10": "urn:schemas-microsoft-com:office:word",
12 | "@xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
13 | "@xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
14 | "@xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml",
15 | "@xmlns:wpg": "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
16 | "@xmlns:wpi": "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
17 | "@xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml",
18 | "@xmlns:wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
19 | "@mc:Ignorable": "w14 w15 wp14",
20 | "w:body": {
21 | "w:p": {
22 | "@w:rsidR": "00656562",
23 | "@w:rsidRDefault": "00B42A0D",
24 | "w:r": {
25 | "w:t": "Hello, world."
26 | },
27 | "w:bookmarkStart": {
28 | "@w:id": "0",
29 | "@w:name": "_GoBack"
30 | },
31 | "w:bookmarkEnd": {
32 | "@w:id": "0"
33 | }
34 | },
35 | "w:sectPr": {
36 | "@w:rsidR": "00656562",
37 | "w:pgSz": {
38 | "@w:w": "11906",
39 | "@w:h": "16838"
40 | },
41 | "w:pgMar": {
42 | "@w:top": "1440",
43 | "@w:right": "1440",
44 | "@w:bottom": "1440",
45 | "@w:left": "1440",
46 | "@w:header": "708",
47 | "@w:footer": "708",
48 | "@w:gutter": "0"
49 | },
50 | "w:cols": {
51 | "@w:space": "708"
52 | },
53 | "w:docGrid": {
54 | "@w:linePitch": "360"
55 | }
56 | }
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/test/purchaseorder.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Purchase order schema for Example.com.
6 | Copyright 2000 Example.com. All rights reserved.
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/out/sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": {
3 | "@xmlns": "http://www.w3.org/ns/wsdl",
4 | "@xmlns:tns": "http://www.tmsws.com/wsdl20sample",
5 | "@xmlns:whttp": "http://schemas.xmlsoap.org/wsdl/http/",
6 | "@xmlns:wsoap": "http://schemas.xmlsoap.org/wsdl/soap/",
7 | "@targetNamespace": "http://www.tmsws.com/wsdl20sample",
8 | "documentation": "This is a sample WSDL 2.0 document.",
9 | "types": {
10 | "xs:schema": {
11 | "@xmlns:xs": "http://www.w3.org/2001/XMLSchema",
12 | "@xmlns": "http://www.tmsws.com/wsdl20sample",
13 | "@targetNamespace": "http://www.example.com/wsdl20sample",
14 | "xs:element": [
15 | {
16 | "@name": "request",
17 | "#text": "..."
18 | },
19 | {
20 | "@name": "response",
21 | "#text": "..."
22 | }
23 | ]
24 | }
25 | },
26 | "interface": {
27 | "@name": "Interface1",
28 | "fault": {
29 | "@name": "Error1",
30 | "@element": "tns:response"
31 | },
32 | "operation": {
33 | "@name": "Get",
34 | "@pattern": "http://www.w3.org/ns/wsdl/in-out",
35 | "input": {
36 | "@messageLabel": "In",
37 | "@element": "tns:request"
38 | },
39 | "output": {
40 | "@messageLabel": "Out",
41 | "@element": "tns:response"
42 | }
43 | }
44 | },
45 | "binding": [
46 | {
47 | "@name": "HttpBinding",
48 | "@interface": "tns:Interface1",
49 | "@type": "http://www.w3.org/ns/wsdl/http",
50 | "operation": {
51 | "@ref": "tns:Get",
52 | "@whttp:method": "GET"
53 | }
54 | },
55 | {
56 | "@name": "SoapBinding",
57 | "@interface": "tns:Interface1",
58 | "@type": "http://www.w3.org/ns/wsdl/soap",
59 | "@wsoap:protocol": "http://www.w3.org/2003/05/soap/bindings/HTTP/",
60 | "@wsoap:mepDefault": "http://www.w3.org/2003/05/soap/mep/request-response",
61 | "operation": {
62 | "@ref": "tns:Get"
63 | }
64 | }
65 | ],
66 | "service": {
67 | "@name": "Service1",
68 | "@interface": "tns:Interface1",
69 | "endpoint": [
70 | {
71 | "@name": "HttpEndpoint",
72 | "@binding": "tns:HttpBinding",
73 | "@address": "http://www.example.com/rest/"
74 | },
75 | {
76 | "@name": "SoapEndpoint",
77 | "@binding": "tns:SoapBinding",
78 | "@address": "http://www.example.com/soap/"
79 | }
80 | ]
81 | }
82 | }
83 | }
--------------------------------------------------------------------------------
/examples/jpath.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var x2j = require('../xml2json');
6 | var jpath = require('../jpath');
7 |
8 | function dumpResults(tree,query) {
9 | console.log();
10 | console.log(query);
11 | var matches = jpath.select(tree,query);
12 | for (var m in matches) {
13 | console.log(matches[m].value ? matches[m].value : matches[m]);
14 | }
15 | return matches;
16 | }
17 |
18 | function testBookStore(tree) {
19 | console.log();
20 | console.log('That looks like a bookstore!');
21 |
22 | dumpResults(tree,'$..*');
23 | dumpResults(tree,'*');
24 | dumpResults(tree,'$.store.book[*].author');
25 | dumpResults(tree,'$..author');
26 | dumpResults(tree,'$.store.*');
27 | dumpResults(tree,'$.store..price');
28 | dumpResults(tree,'$..book[2]');
29 | dumpResults(tree,'$..book[2].price');
30 | dumpResults(tree,'$..bicycle.price');
31 | dumpResults(tree,'$..bicycle.price^');
32 | }
33 |
34 | function propTest(obj,path) {
35 | console.log(path+' = '+jpath.fetchFromObject(obj,path))
36 | }
37 |
38 | function ptrTest(obj,path) {
39 | console.log(path+' = '+jpath.jptr(obj,path))
40 | }
41 |
42 | function testProperties(obj) {
43 | console.log();
44 | propTest(obj,'store.book[2].price');
45 | ptrTest(obj,'/store/book/2/price');
46 | jpath.jptr(obj,'/store/book/2/price',10.99);
47 | ptrTest(obj,'/store/book/2/price');
48 | }
49 |
50 | var filename = process.argv[2] || path.resolve(__dirname,'../test/bookstore.json');
51 | var valueProperty = false;
52 | if (process.argv.length>3) {
53 | valueProperty = true;
54 | }
55 |
56 | var xml = fs.readFileSync(filename,'utf8');
57 |
58 | try {
59 | var obj = x2j.xml2json(xml,{"attributePrefix": "@","valueProperty": valueProperty, "coerceTypes": false});
60 | }
61 | catch (err) {
62 | console.error('That is not valid JSON');
63 | console.error(err);
64 | console.log(xml);
65 | console.log();
66 | console.log(x2j.getString());
67 | process.exit(1);
68 | }
69 |
70 | var tree = jpath.build(obj);
71 | // we could do a select('*') here but it's redundant unless we want the bracketed form
72 | for (var i in tree) {
73 | // log our jpath for every item
74 | console.log(tree[i].depth+' '+jpath.path(tree[i],false)+' = '+tree[i].value);
75 | }
76 |
77 | if (tree.length>0) {
78 | if (obj.store && obj.store.book) {
79 | testBookStore(tree);
80 | testProperties(obj);
81 | }
82 | else {
83 | // generic examples
84 | var first = jpath.path(tree[1]);
85 | var matches = jpath.select(tree,first);
86 | for (var m in matches) {
87 | console.log('First; select('+jpath.path(matches[m])+') = '+matches[m].value);
88 | }
89 |
90 | var last = tree[tree.length-1];
91 | console.log('Last; select('+jpath.path(last,true)+',true) = '+last.value);
92 | console.log(last.prefix)
93 |
94 | var parents = jpath.select(tree,last.prefix);
95 | if (parents.length>0) {
96 | var value = parents[0].value;
97 | if (typeof(value) === 'object') {
98 | value = JSON.stringify(value,null,2);
99 | }
100 | console.log('select('+jpath.path(parents[0],true)+',true) = '+value);
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/test/structure.invalid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
9 |
13 |
14 |
19 |
20 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
49 |
50 |
55 |
60 |
61 |
66 |
71 |
72 |
77 |
78 |
83 |
84 |
85 |
86 |
91 |
92 |
96 |
97 |
98 |
103 |
104 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jgeXml - The Just-Good-Enough XML Toolkit
2 |
3 | [](https://travis-ci.org/Mermade/jgeXml)
4 | [](https://join.slack.com/t/mermade/shared_invite/zt-g78g7xir-MLE_CTCcXCdfJfG3CJe9qA)
5 |
6 | [![Share on Twitter][twitter-image]][twitter-link]
7 | [![Follow on Twitter][twitterFollow-image]][twitterFollow-link]
8 |
9 | jgeXml provides an event-driven parser to process XML 1.0 / 1.1. Both pull and push modes are supported. Tools are included for writing XML (documents or fragments) and to convert between XML and JSON.
10 |
11 | The code has no dependencies on other modules or native libraries.
12 |
13 | Setting up a push-parser is as simple as:
14 |
15 | ```javascript
16 | const jgexml = require('jgexml');
17 | const result = jgexml.parse(xml, function(state, token) {
18 | //...
19 | });
20 | ```
21 |
22 | ## Events (stateCodes)
23 |
24 | * `sDeclaration`
25 | * `sDocType`
26 | * `sDTD`
27 | * `sElement`
28 | * `sAttribute`
29 | * `sValue`
30 | * `sEndElement`
31 | * `sContent`
32 | * `sComment`
33 | * `sProcessingInstruction`
34 | * `sCData`
35 | * `sError`
36 | * `sEndDocument`
37 |
38 | No event is generated for ignoreable whitespace, unlike SAX. Empty elements are normalised into sElement/sEndElement pairs.
39 |
40 | ## Notes
41 |
42 | jgeXml is a non-validating parser. It attempts to report if the XML is well-formed or not.
43 |
44 | Both when reading and writing, attributes follow after the element event, and in the order they are given in the source.
45 |
46 | When converting to JSON, the attributePrefix (to avoid name clashes with child elements) is configurable per parse.
47 |
48 | In JSON, child elements can be represented as properties (the default) or objects (exposing the parser's intermediary state).
49 |
50 | The parser by default treats all content as strings when converting to JSON, optionally data can be coerced to primitive numbers or null values.
51 |
52 | The `xsd2json` utility can convert most simple XML Schemas to JSON schema draft 4. XSD's may of course be converted to JSON simply as if they were XML documents too.
53 |
54 | Experimental JSONPath and JSONT utilities are under development.
55 |
56 | ## Limitations
57 |
58 | jgeXml is currently schema agnostic and staunchly atheist when it comes to DTDs. It can parse XML documents with schema information, but it is up to the
59 | consumer to interpret the namespace portions of element names. It can parse internal DTDs, but does nothing with them.
60 | `xmlWrite` minimally supports DTDs but you must build them and the DOCTYPE yourself.
61 |
62 | The parser is string-based; to process streams, read the data into a string first. It may be memory intensive on large documents.
63 |
64 | ## CLI commands
65 |
66 | * `xml2json` - convert XML to JSON.
67 | * `json2xml` - convert JSON to XML.
68 | * `xsd2json` - convert XSD to JSON Schema.
69 |
70 | ## Examples
71 |
72 | See in the `examples` directory: `xml2xml.js` for parsing XML to XML, `fragment.js` for writing XML fragments, `jpath.js` for JSONPath examples, `jsont.js` for JSONT examples and `pullparser.js` / `pushparser.js` for how to set up and run the parser.
73 |
74 | [twitter-image]: https://img.shields.io/twitter/url/http/PermittedSoc.svg?style=social
75 | [twitter-link]: https://twitter.com/share?source=tweetbutton&text=jgeXml%20parser%20Via%20%40PermittedSoc&url=https%3A%2F%2Fgithub.com%2FMikeRalphson%2FjgeXml
76 | [twitterFollow-image]: https://img.shields.io/twitter/follow/PermittedSoc.svg?style=social
77 | [twitterFollow-link]: https://twitter.com/intent/follow?screen_name=PermittedSoc
78 |
--------------------------------------------------------------------------------
/xmlWrite.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var xml = '';
4 | var hanging = '';
5 | var followsElement = true;
6 | var followsEndElement = false;
7 | var depth = 0;
8 | var pretty = 0;
9 | var spacer = ' ';
10 |
11 | function replaceAll(s, from, to) {
12 | return s.split(from).join(to);
13 | }
14 |
15 | function encode(s) {
16 | var es = s;
17 | if (typeof s === 'string') { // might be a number, boolean or null
18 | es = replaceAll(es, '&','&');
19 | es = replaceAll(es, '<','<');
20 | es = replaceAll(es, '>','>');
21 | es = replaceAll(es, '"','"');
22 | es = replaceAll(es, "'",''');
23 | }
24 | return es;
25 | }
26 |
27 | function startFragment(indent,indentStr) {
28 | if (indent) {
29 | pretty = indent;
30 | if ((indentStr) && (indentStr !== '')) {
31 | spacer = indentStr;
32 | }
33 | else {
34 | spacer = ' ';
35 | }
36 | }
37 | else {
38 | pretty = 0;
39 | }
40 |
41 | followsElement = true;
42 | followsEndElement = false;
43 | xml = '';
44 | hanging = '';
45 | depth = 0;
46 | }
47 |
48 | module.exports = {
49 | startFragment: startFragment,
50 |
51 | startDocument : function (encoding,standalone,indent,indentStr) {
52 | startFragment(indent,indentStr);
53 | xml = '';
55 | },
56 |
57 | docType : function (s) {
58 | xml += '';
59 | },
60 |
61 | startElement : function (s) {
62 | xml += hanging;
63 | if (s !== '') {
64 | if ((pretty) && (followsElement || followsEndElement)) xml += '\n'+new Array(pretty*depth+1).join(spacer);
65 | xml += '<' + s;
66 | hanging = '>';
67 | depth++;
68 | followsElement = true;
69 | }
70 | else hanging = '';
71 | },
72 |
73 | emptyElement : function (s) {
74 | xml += hanging + '<' + s;
75 | hanging = '/>';
76 | },
77 |
78 | attribute : function (a,v) {
79 | xml += ' ' + a + '="' + encode(v) + '"';
80 | },
81 |
82 | content : function (s) {
83 | xml += hanging + encode(s);
84 | hanging = '';
85 | followsElement = false;
86 | followsEndElement = false;
87 | },
88 |
89 | comment : function (s) {
90 | xml += hanging + '';
91 | hanging = '';
92 | },
93 |
94 | processingInstruction : function (s) {
95 | xml += hanging;
96 | if ((pretty) && (followsElement || followsEndElement)) xml += '\n'+new Array(pretty*depth+1).join(spacer);
97 | xml += '' + encode(s) + '?>';
98 | hanging = '';
99 | },
100 |
101 | cdata : function (s) {
102 | xml += hanging;
103 | if ((pretty) && (followsElement || followsEndElement)) xml += '\n'+new Array(pretty*depth+1).join(spacer);
104 | xml += '';
105 | hanging = '';
106 | },
107 |
108 | fragment : function (s) {
109 | xml += hanging + s;
110 | hanging = '';
111 | followsElement = false;
112 | followsEndElement = true;
113 | },
114 |
115 | endElement : function (s) {
116 | var suppress = false;
117 | if (hanging == '>') {
118 | hanging = '/>';
119 | suppress = true;
120 | }
121 | xml += hanging;
122 | if (s !== '') {
123 | depth--;
124 | if (!suppress) {
125 | if (pretty && followsEndElement) xml += '\n'+new Array(pretty*depth+1).join(spacer);
126 | xml += '' + s + '>';
127 | }
128 | followsElement = false;
129 | followsEndElement = true;
130 | }
131 | hanging = '';
132 | },
133 |
134 | endFragment : function () {
135 | xml += hanging;
136 | hanging = '';
137 | return xml;
138 | },
139 |
140 | endDocument : function () {
141 | //hanging is '' at this point
142 | return xml;
143 | }
144 | };
145 |
--------------------------------------------------------------------------------
/xml2json.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var jgeXml = require('./jgeXml.js');
5 |
6 | function filterInt(value) {
7 | if (/^(\-|\+)?([0-9]+|Infinity)$/.test(value)) return Number(value);
8 | return NaN;
9 | }
10 |
11 | function filterFloat(value) {
12 | if(/^(\-|\+)?([0-9]*(\.[0-9]+)?|Infinity)$/.test(value)) return Number(value);
13 | return NaN;
14 | }
15 |
16 | function emit(token,coerceTypes) {
17 | if (coerceTypes) {
18 | var timestamp = Date.parse(token);
19 | if (!isNaN(timestamp) && (token.match('^[0-9]{4}\-[0-9]{2}\-[0-9]{2}.*$'))) {
20 | return token;
21 | }
22 | var num = filterFloat(token);
23 | if (!isNaN(num)) {
24 | return num;
25 | }
26 | num = filterInt(token); //parseInt
27 | if (!isNaN(num)) {
28 | return num;
29 | }
30 | if ((token === 'true') || (token === 'false')) {
31 | return token === 'true';
32 | }
33 | if ((Object.keys(token).length === 0) || (token == 'xsi:nil')) {
34 | return 'null';
35 | }
36 | }
37 | return token;
38 | }
39 |
40 | function getString() {
41 | // deprecated
42 | return '';
43 | }
44 |
45 | function postProcess(obj,parent,options) {
46 |
47 | for (var key in obj) {
48 | // skip loop if the property is from prototype
49 | if (!obj.hasOwnProperty(key)) continue;
50 |
51 | var propArray = Array.isArray(obj[key]);
52 | if (propArray && obj[key].length == 1) {
53 | obj[key] = obj[key][0];
54 | }
55 | if ((typeof obj[key] == 'object') && (parent !== '')) {
56 | var firstKey = Object.keys(obj[key])[0];
57 | if ((firstKey == options.textName) || (firstKey == options.valName)) {
58 | if ((Object.keys(obj[key]).length == 1) && (typeof obj[key][firstKey] != 'object')) {
59 | obj[key] = obj[key][firstKey];
60 | }
61 | }
62 | }
63 |
64 | if (typeof obj[key] == 'object') {
65 | postProcess(obj[key],key,options);
66 | }
67 | }
68 | return obj;
69 | }
70 |
71 | function parseString(xml,options) {
72 |
73 | var stack = [];
74 | var context = {};
75 | var lastElement = '';
76 |
77 | var defaults = {
78 | attributePrefix: "@",
79 | textName: '#text',
80 | valName: '#value',
81 | valueProperty: false,
82 | coerceTypes: false
83 | };
84 |
85 | options = Object.assign({},defaults,options); // merge/extend
86 |
87 | var obj = {};
88 | var newCursor = obj;
89 | var cursor = obj;
90 |
91 | var currentElementName = '';
92 | var currentAttributeName = '';
93 | var index = -1;
94 |
95 | jgeXml.parse(xml,function(state,token) {
96 |
97 | if (state == jgeXml.sElement) {
98 | var parentElementName = currentElementName;
99 |
100 | context = {};
101 | context.cursor = newCursor;
102 | context.parent = cursor;
103 | context.index = index;
104 | context.elementName = currentElementName;
105 | stack.push(context);
106 |
107 | cursor = newCursor;
108 | currentElementName = token;
109 |
110 | if (newCursor[currentElementName]) {
111 | var n = {};
112 | newCursor[currentElementName].push(n);
113 | index = newCursor[currentElementName].length-1;
114 | newCursor = n;
115 | }
116 | else {
117 | newCursor[currentElementName] = [{}]; // we start off assuming each element is an object in an array not just a property
118 | newCursor = newCursor[currentElementName][0];
119 | index = 0;
120 | }
121 | }
122 | else if ((state == jgeXml.sContent) || (state == jgeXml.sCData)) {
123 | token = emit(token,options.coerceTypes);
124 | var target = cursor[currentElementName][index][options.textName];
125 | if (!target) {
126 | target = cursor[currentElementName][index][options.textName] = [];
127 | }
128 | var nt = {};
129 | nt[options.valName] = token;
130 | target.push(nt);
131 | }
132 | else if (state == jgeXml.sEndElement) {
133 | // finish up
134 | context = stack[stack.length-1];
135 | currentElementName = context.elementName;
136 | newCursor = context.cursor;
137 | cursor = context.parent;
138 | index = context.index;
139 |
140 | stack.pop();
141 | }
142 | else if (state == jgeXml.sAttribute) {
143 | currentAttributeName = options.attributePrefix+token;
144 | }
145 | else if (state == jgeXml.sValue) {
146 | token = emit(token,options.coerceTypes);
147 | cursor[currentElementName][index][currentAttributeName] = token;
148 | }
149 | });
150 |
151 | if (!options.valueProperty) {
152 | obj = postProcess(obj,'',options); // first pass
153 | obj = postProcess(obj,'',options); // second pass
154 | }
155 |
156 | return obj;
157 | }
158 |
159 | module.exports = {
160 | xml2json : parseString,
161 | getString : getString
162 | };
--------------------------------------------------------------------------------
/out/purchaseorder.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/purchaseorder.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "description": "Purchase order schema for Example.com.\n Copyright 2000 Example.com. All rights reserved.",
5 | "type": "object",
6 | "properties": {
7 | "purchaseOrder": {
8 | "$ref": "#/definitions/PurchaseOrderType"
9 | }
10 | },
11 | "required": [
12 | "purchaseOrder"
13 | ],
14 | "additionalProperties": false,
15 | "definitions": {
16 | "comment": {
17 | "type": "string"
18 | },
19 | "PurchaseOrderType": {
20 | "type": "object",
21 | "properties": {
22 | "shipTo": {
23 | "$ref": "#/definitions/USAddress"
24 | },
25 | "billTo": {
26 | "$ref": "#/definitions/USAddress"
27 | },
28 | "comment": {
29 | "$ref": "#/definitions/comment"
30 | },
31 | "items": {
32 | "$ref": "#/definitions/Items"
33 | },
34 | "orderDate": {
35 | "type": "string",
36 | "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}.*$"
37 | }
38 | },
39 | "required": [
40 | "shipTo",
41 | "billTo",
42 | "items"
43 | ],
44 | "additionalProperties": false
45 | },
46 | "USAddress": {
47 | "type": "object",
48 | "properties": {
49 | "name": {
50 | "type": "string"
51 | },
52 | "street": {
53 | "type": "string"
54 | },
55 | "city": {
56 | "type": "string"
57 | },
58 | "state": {
59 | "type": "string"
60 | },
61 | "zip": {
62 | "type": "number"
63 | },
64 | "country": {
65 | "type": "string",
66 | "enum": [
67 | "US"
68 | ]
69 | }
70 | },
71 | "required": [
72 | "name",
73 | "street",
74 | "city",
75 | "state",
76 | "zip"
77 | ],
78 | "additionalProperties": false
79 | },
80 | "Items": {
81 | "type": "object",
82 | "properties": {
83 | "item": {
84 | "type": "array",
85 | "items": {
86 | "type": "object",
87 | "properties": {
88 | "productName": {
89 | "type": "string"
90 | },
91 | "quantity": {
92 | "type": "integer",
93 | "minimum": 1
94 | },
95 | "USPrice": {
96 | "type": "number"
97 | },
98 | "comment": {
99 | "$ref": "#/definitions/comment"
100 | },
101 | "shipDate": {
102 | "type": "string",
103 | "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}.*$"
104 | },
105 | "partNum": {
106 | "$ref": "#/definitions/SKU"
107 | },
108 | "item": {
109 | "type": "array",
110 | "items": {
111 | "type": "object",
112 | "properties": {
113 | "productName": {
114 | "type": "string"
115 | },
116 | "quantity": {
117 | "type": "integer",
118 | "minimum": 1
119 | },
120 | "USPrice": {
121 | "type": "number"
122 | },
123 | "comment": {
124 | "$ref": "#/definitions/comment"
125 | },
126 | "shipDate": {
127 | "type": "string",
128 | "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}.*$"
129 | },
130 | "partNum": {
131 | "$ref": "#/definitions/SKU"
132 | }
133 | },
134 | "required": [
135 | "productName",
136 | "quantity",
137 | "USPrice",
138 | "partNum"
139 | ],
140 | "additionalProperties": false
141 | }
142 | }
143 | },
144 | "required": [
145 | "productName",
146 | "quantity",
147 | "USPrice",
148 | "partNum"
149 | ],
150 | "additionalProperties": false
151 | }
152 | }
153 | },
154 | "additionalProperties": false
155 | },
156 | "SKU": {
157 | "type": "string",
158 | "pattern": "\\d{3}-[A-Z]{2}"
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/test/pc_hd_abr_v2_dash_master.coerceTypes.noap.mpd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
14 | dash/
15 |
26 |
29 |
30 |
33 |
34 |
40 |
41 |
44 |
45 |
46 |
61 |
64 |
65 |
73 |
79 |
80 |
81 |
89 |
95 |
96 |
97 |
105 |
111 |
112 |
113 |
121 |
127 |
128 |
129 |
137 |
143 |
144 |
145 |
153 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/out/pc_hd_abr_v2_dash_master.coerceTypes.noap.json:
--------------------------------------------------------------------------------
1 | {
2 | "MPD": {
3 | "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
4 | "xmlns": "urn:mpeg:dash:schema:mpd:2011",
5 | "xsi:schemaLocation": "urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd",
6 | "type": "static",
7 | "mediaPresentationDuration": "PT29M24.400S",
8 | "maxSegmentDuration": "PT4S",
9 | "minBufferTime": "PT1.920S",
10 | "profiles": "urn:dvb:dash:profile:dvb-dash:2014,urn:dvb:dash:profile:dvb-dash:isoff-ext-live:2014",
11 | "Period": {
12 | "duration": "PT29M24.400S",
13 | "BaseURL": "dash/",
14 | "AdaptationSet": [
15 | {
16 | "group": 1,
17 | "contentType": "audio",
18 | "lang": "en",
19 | "minBandwidth": 96000,
20 | "maxBandwidth": 96000,
21 | "segmentAlignment": true,
22 | "audioSamplingRate": 48000,
23 | "mimeType": "audio/mp4",
24 | "codecs": "mp4a.40.5",
25 | "startWithSAP": 1,
26 | "AudioChannelConfiguration": {
27 | "schemeIdUri": "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
28 | "value": 2
29 | },
30 | "Role": {
31 | "schemeIdUri": "urn:mpeg:dash:role:2011",
32 | "value": "main"
33 | },
34 | "SegmentTemplate": {
35 | "timescale": 24000,
36 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
37 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
38 | "startNumber": 1,
39 | "duration": 92160
40 | },
41 | "Representation": {
42 | "id": "audio_1=96000",
43 | "bandwidth": 96000
44 | }
45 | },
46 | {
47 | "group": 2,
48 | "contentType": "video",
49 | "par": "16:9",
50 | "minBandwidth": 281000,
51 | "maxBandwidth": 5070000,
52 | "minWidth": 384,
53 | "maxWidth": 1280,
54 | "minHeight": 216,
55 | "maxHeight": 720,
56 | "minFrameRate": 25,
57 | "maxFrameRate": 50,
58 | "segmentAlignment": true,
59 | "mimeType": "video/mp4",
60 | "startWithSAP": 1,
61 | "Role": {
62 | "schemeIdUri": "urn:mpeg:dash:role:2011",
63 | "value": "main"
64 | },
65 | "Representation": [
66 | {
67 | "id": "video=281000",
68 | "bandwidth": 281000,
69 | "width": 384,
70 | "height": 216,
71 | "frameRate": 25,
72 | "codecs": "avc3.42C015",
73 | "scanType": "progressive",
74 | "SegmentTemplate": {
75 | "timescale": 25000,
76 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
77 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
78 | "startNumber": 1,
79 | "duration": 96000
80 | }
81 | },
82 | {
83 | "id": "video=437000",
84 | "bandwidth": 437000,
85 | "width": 512,
86 | "height": 288,
87 | "frameRate": 25,
88 | "codecs": "avc3.4D401E",
89 | "scanType": "progressive",
90 | "SegmentTemplate": {
91 | "timescale": 25000,
92 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
93 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
94 | "startNumber": 1,
95 | "duration": 96000
96 | }
97 | },
98 | {
99 | "id": "video=827000",
100 | "bandwidth": 827000,
101 | "width": 704,
102 | "height": 396,
103 | "frameRate": 25,
104 | "codecs": "avc3.4D401E",
105 | "scanType": "progressive",
106 | "SegmentTemplate": {
107 | "timescale": 25000,
108 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
109 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
110 | "startNumber": 1,
111 | "duration": 96000
112 | }
113 | },
114 | {
115 | "id": "video=1604000",
116 | "bandwidth": 1604000,
117 | "width": 960,
118 | "height": 540,
119 | "frameRate": 25,
120 | "codecs": "avc3.4D401F",
121 | "scanType": "progressive",
122 | "SegmentTemplate": {
123 | "timescale": 25000,
124 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
125 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
126 | "startNumber": 1,
127 | "duration": 96000
128 | }
129 | },
130 | {
131 | "id": "video=2812000",
132 | "bandwidth": 2812000,
133 | "width": 960,
134 | "height": 540,
135 | "frameRate": 50,
136 | "codecs": "avc3.64001F",
137 | "scanType": "progressive",
138 | "SegmentTemplate": {
139 | "timescale": 50000,
140 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
141 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
142 | "startNumber": 1,
143 | "duration": 192000
144 | }
145 | },
146 | {
147 | "id": "video=5070000",
148 | "bandwidth": 5070000,
149 | "width": 1280,
150 | "height": 720,
151 | "frameRate": 50,
152 | "codecs": "avc3.640020",
153 | "scanType": "progressive",
154 | "SegmentTemplate": {
155 | "timescale": 50000,
156 | "initialization": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$.dash",
157 | "media": "vf_b05tr53t_8233510d-66fb-462e-8e22-deb72abc9c6c-$RepresentationID$-$Number$.m4s",
158 | "startNumber": 1,
159 | "duration": 192000
160 | }
161 | }
162 | ]
163 | }
164 | ]
165 | }
166 | }
167 | }
168 |
169 |
--------------------------------------------------------------------------------
/test/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
96 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/jpath.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * escapes JSON Pointer using ~0 for ~ and ~1 for /
5 | * @param s the string to escape
6 | * @return the escaped string
7 | */
8 | function jpescape(s) {
9 | return s.replace(/\~/g, '~0').replace(/\//g, '~1');
10 | }
11 |
12 | /**
13 | * unescapes JSON Pointer using ~0 for ~ and ~1 for /
14 | * @param s the string to unescape
15 | * @return the unescaped string
16 | */
17 | function jpunescape(s) {
18 | return s.replace(/\~1/g, '/').replace(/~0/g, '~');
19 | }
20 |
21 | // JSON Pointer specification: http://tools.ietf.org/html/rfc6901
22 |
23 | /**
24 | * from obj, return the property with a JSON Pointer prop, optionally setting it
25 | * to newValue
26 | * @param obj the object to point into
27 | * @param prop the JSON Pointer or JSON Reference
28 | * @param newValue optional value to set the property to
29 | * @return the found property, or false
30 | */
31 | function jptr(obj, prop, newValue) {
32 | if (typeof obj === 'undefined') return false;
33 | if (!prop || typeof prop !== 'string' || (prop === '#')) return (typeof newValue !== 'undefined' ? newValue : obj);
34 |
35 | if (prop.indexOf('#')>=0) {
36 | let parts = prop.split('#');
37 | let uri = parts[0];
38 | if (uri) return false; // we do internal resolution only
39 | prop = parts[1];
40 | prop = decodeURIComponent(prop.slice(1).split('+').join(' '));
41 | }
42 | if (prop.startsWith('/')) prop = prop.slice(1);
43 |
44 | let components = prop.split('/');
45 | for (let i=0;i 0) ? components[i-1] : ''; // backtrack to indexed property name
56 | }
57 |
58 | if ((index != -1) || obj.hasOwnProperty(components[i])) {
59 | if (index >= 0) {
60 | if (setAndLast) {
61 | obj[index] = newValue;
62 | }
63 | obj = obj[index];
64 | }
65 | else if (index === -2) {
66 | if (setAndLast) {
67 | if (Array.isArray(obj)) {
68 | obj.push(newValue);
69 | }
70 | return newValue;
71 | }
72 | else return undefined;
73 | }
74 | else {
75 | if (setAndLast) {
76 | obj[components[i]] = newValue;
77 | }
78 | obj = obj[components[i]];
79 | }
80 | }
81 | else {
82 | if ((typeof newValue !== 'undefined') && (typeof obj === 'object') &&
83 | (!Array.isArray(obj))) {
84 | obj[components[i]] = (setAndLast ? newValue : ((components[i+1] === '0' || components[i+1] === '-') ? [] : {}));
85 | obj = obj[components[i]];
86 | }
87 | else return false;
88 | }
89 | }
90 | return obj;
91 | }
92 |
93 | // simple object accessor using dotted notation and [] for array indices
94 | function fetchFromObject(obj, prop, newValue) {
95 | //property not found
96 | if (typeof obj === 'undefined') return false;
97 | if (!prop) {
98 | if (typeof newValue != 'undefined') {
99 | obj = newValue;
100 | }
101 | return obj;
102 | }
103 |
104 | var props = prop.split('.');
105 | var arr = props[0].split(/[\[\]]+/);
106 | var index = -1;
107 | if (arr.length>1) {
108 | index = parseInt(arr[1],10);
109 | }
110 |
111 | //property split found; recursive call
112 | if (props.length>1) {
113 | var pos = prop.indexOf('.');
114 | //get object at property (before split), pass on remainder
115 | if (index>=0) {
116 | return fetchFromObject(obj[arr[0]][index], prop.substr(pos+1), newValue); //was props
117 | }
118 | else {
119 | return fetchFromObject(obj[arr[0]], prop.substr(pos+1), newValue);
120 | }
121 | }
122 | //no split; get property[index] or property
123 | var source = obj;
124 | if (arr[0]) source = obj[prop];
125 | if (index>=0) {
126 | if (typeof newValue != 'undefined') source[index] = newValue;
127 | return source[index];
128 | }
129 | else {
130 | if (typeof newValue != 'undefined') obj[prop] = newValue;
131 | return obj[prop];
132 | }
133 | }
134 |
135 | function traverse(obj,prefix,depth,parent) {
136 |
137 | var result = [];
138 |
139 | for (var key in obj) {
140 | // skip loop if the property is from prototype
141 | if (!obj.hasOwnProperty(key)) continue;
142 |
143 | var display = key;
144 | var sep = '.';
145 | if (Array.isArray(obj)) {
146 | display = '['+key+']';
147 | sep = '';
148 | }
149 |
150 | var item = {};
151 | item.prefix = prefix;
152 | item.key = key;
153 | item.display = display;
154 | item.value = obj[key];
155 | item.depth = depth;
156 | item.parent = parent;
157 | result.push(item);
158 | if (typeof obj[key] === 'object') {
159 | result = result.concat(traverse(obj[key],prefix+sep+display,depth+1,obj));
160 | }
161 | }
162 | return result;
163 | }
164 |
165 | function path(item,bracketed) {
166 | if (bracketed) {
167 | var result = '';
168 | var parents = item.prefix.split('.');
169 | for (var p=0;p 0) && (target != '$..*')) {
225 | var x = target.split('..');
226 | target = x[x.length-1];
227 | target = target.split('$').join('');
228 | checkEnd = true;
229 | }
230 |
231 | for (var i=0;i l2.length ? l2.length : l1.length;
31 | for (var l=0;l=0) {
68 | attrPrefix = '';
69 | }
70 | var obj = x2j.xml2json(xml,{"attributePrefix": attrPrefix, "valueProperty": valueProperty, "coerceTypes": coerceTypes});
71 | var json = JSON.stringify(obj,null,2);
72 | var compare = fs.readFileSync('out/'+stem+'.json',encoding);
73 | compare = compare.replaceAll('\r\n','\n');
74 |
75 | if (json.trim() == compare.trim()) {
76 | passing++;
77 | }
78 | else {
79 | diff(json,compare);
80 | console.log(' Fail');
81 | failing++;
82 | }
83 |
84 | exists = false;
85 | try {
86 | fs.statSync('out/'+stem+'.jpath',fs.R_OK);
87 | exists = true;
88 | }
89 | catch(err) {}
90 |
91 | if (exists) {
92 | console.log(' Test JSONPath');
93 | var jpt = fs.readFileSync('out/'+stem+'.jpath',encoding);
94 | var jpo = JSON.parse(jpt);
95 |
96 | var tree = jpath.build(obj);
97 | var success = true;
98 |
99 | for (var j in jpo) {
100 | var test = jpo[j];
101 |
102 | var query = test.query;
103 | var fetch = test.fetch;
104 | var expected = test.expected;
105 |
106 | var output = jpath.select(tree,query)[0].value;
107 |
108 | if ((expected != output) || (expected != jpath.fetchFromObject(obj,fetch))) {
109 | console.log(output);
110 | console.log(jpath.fetchFromObject(obj,fetch));
111 | console.log(expected);
112 | success = false;
113 | }
114 |
115 | }
116 | if (!success) {
117 | console.log(' Fail jpath');
118 | failing++;
119 | }
120 | }
121 |
122 | }
123 | }
124 |
125 | function runXsdTest(filename,components) {
126 | var stem = '';
127 | for (var c=0;c=0);
143 | var obj = xsd2j.getJsonSchema(j1,testdir+'/'+filename,'',laxUris);
144 | var json = JSON.stringify(obj,null,2);
145 | var compare = fs.readFileSync('out/'+stem+'.json',encoding);
146 | compare = compare.replaceAll('\r\n','\n');
147 |
148 | if (json.trim() == compare.trim()) {
149 | passing++;
150 | }
151 | else {
152 | diff(json,compare);
153 | console.log(' Fail');
154 | failing++;
155 | }
156 | }
157 | }
158 |
159 | function runJsonTest(filename,components) {
160 | var stem = '';
161 | for (var c=0;c2) testdir = process.argv[2];
236 |
237 | var xmlTypes = ['xml','xsl','xhtml','svg','wsdl','config', 'mpd'];
238 |
239 | var tests = fs.readdirSync(testdir);
240 | for (var t in tests) {
241 | var filename = tests[t];
242 | console.log(filename);
243 | var components = filename.split('.');
244 |
245 | encoding = 'utf8';
246 | if (components.indexOf('utf16') >= 0) encoding = 'ucs2';
247 |
248 | valueProperty = false;
249 | if (components.indexOf('valueProperty') >= 0) valueProperty = true;
250 |
251 | coerceTypes = false;
252 | if (components.indexOf('coerceTypes') >= 0) coerceTypes = true;
253 |
254 | if ((xmlTypes.indexOf(components[components.length-1]) >= 0) && (components.indexOf('invalid') >= 0)) {
255 | testXml(filename,components,false);
256 | }
257 | else if (xmlTypes.indexOf(components[components.length-1]) >= 0) {
258 | if (components.indexOf('pull') >= 0) {
259 | testXmlPull(filename,components,true);
260 | }
261 | else {
262 | testXml(filename,components,true);
263 | }
264 | runXmlTest(filename,components);
265 | }
266 | else if (components[components.length-1] == 'xsd') {
267 | testXml(filename,components,true);
268 | runXsdTest(filename,components);
269 | }
270 | else if (components[components.length-1] == 'json') {
271 | runJsonTest(filename,components);
272 | }
273 | }
274 |
275 | var frag1 = `
276 |
277 |
278 | baz
279 | `;
280 | var xml = fs.readFileSync('out/fragment1.xml',encoding);
281 | xml = xml.replaceAll('\r','');
282 | if (frag1 == xml) {
283 | passing++;
284 | }
285 | else {
286 | diff(frag1,xml);
287 | failing++;
288 | }
289 |
290 | xw.startFragment(2);
291 | xw.docType('fubar');
292 | xw.startElement('foo');
293 | xw.processingInstruction('nitfol xyzzy');
294 | xw.startElement('bar');
295 | xw.comment('potrzebie');
296 | xw.content('baz');
297 | xw.cdata('snafu');
298 | xw.endElement('bar');
299 | xw.endElement('foo');
300 | frag1 = xw.endFragment();
301 | if (frag1 == xml) {
302 | passing++;
303 | }
304 | else {
305 | diff(frag1,xml);
306 | failing++;
307 | }
308 |
309 | console.log(passing + ' passing, ' + failing + ' failing');
310 | process.exitCode = (failing === 0) ? 0 : 1;
311 |
--------------------------------------------------------------------------------
/jgeXml.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | The Just-Good-Enough XML Parser
4 |
5 | */
6 |
7 | 'use strict';
8 |
9 | const sInitial = 0;
10 | const sDeclaration = 1;
11 | const sPreElement = 2;
12 | const sElement = 3;
13 | const sAttribute = 5;
14 | const sAttrNML = 6; // No Mans Land
15 | const sValue = 7;
16 | const sEndElement = 9;
17 | const sContent = 11;
18 | const sAttributeSpacer = 12;
19 | const sComment = 13;
20 | const sProcessingInstruction = 15;
21 | const sCData = 17;
22 | const sDocType = 19;
23 | const sDTD = 21;
24 | const sError = 23;
25 | const sEndDocument = 25;
26 |
27 | require('./common');
28 |
29 | function stateName(state) {
30 | if (state == sInitial) {
31 | return 'INITIAL';
32 | }
33 | else if (state == sDeclaration) {
34 | return 'DECLARATION';
35 | }
36 | else if (state == sElement) {
37 | return 'ELEMENT';
38 | }
39 | else if (state == sAttribute) {
40 | return 'ATTRIBUTE';
41 | }
42 | else if (state == sValue) {
43 | return 'VALUE';
44 | }
45 | else if (state == sEndElement) {
46 | return 'END_ELEMENT';
47 | }
48 | else if (state == sContent) {
49 | return 'CONTENT';
50 | }
51 | else if (state == sComment) {
52 | return 'COMMENT';
53 | }
54 | else if (state == sProcessingInstruction) {
55 | return 'PROCESSING_INSTRUCTION';
56 | }
57 | else if (state == sCData) {
58 | return 'CDATA';
59 | }
60 | else if (state == sDocType) {
61 | return 'DOCTYPE';
62 | }
63 | else if (state == sDTD) {
64 | return 'DTD';
65 | }
66 | else if (state == sError) {
67 | return 'ERROR';
68 | }
69 | else if (state == sEndDocument) {
70 | return 'END_DOCUMENT';
71 | }
72 | }
73 |
74 | function reset(context) {
75 | context.state = sInitial;
76 | context.newState = sInitial;
77 | context.token = '';
78 | context.boundary = ['','<'];
79 | context.bIndex = -1;
80 | context.lastElement = '';
81 | context.keepToken = false;
82 | context.position = 0;
83 | context.depth = 0;
84 | context.wellFormed = false;
85 | context.validControlChars = ['\t','\r','\n'];
86 | context.error = false;
87 | }
88 |
89 | // to create a push parser, pass in a callback function and omit the context parameter
90 | // to create a pull parser, pass in null for the callback function and initially provide an empty object as the context
91 | function jgeParse(s,callback,context) {
92 |
93 | if (context && context.newState) {
94 | if (!context.keepToken) context.token = '';
95 | context.state = context.newState;
96 | }
97 | else {
98 | context = {};
99 | reset(context);
100 | }
101 |
102 | var c;
103 | for (var i=context.position;i= 0) { //other unicode spaces are not treated as whitespace
111 | c = ' ';
112 | }
113 | }
114 |
115 | context.bIndex = -1;
116 | for (var b=0;b1) {
120 | i = i + context.boundary[context.bIndex].length-1;
121 | }
122 | break;
123 | }
124 | }
125 |
126 | if (context.bIndex >= 0) {
127 |
128 | if ((context.state != sValue) && (context.state != sComment)) { // && (context.state != sContent)
129 | context.token = context.token.trim();
130 | }
131 |
132 | context.keepToken = false;
133 | if (((context.state & 1) == 1) && ((context.token.trim() !== '') || context.state == sValue)) {
134 | // TODO test element names for validity (using regex?)
135 | if (context.state != sCData) {
136 | context.token = context.token.replaceAll('&','&');
137 | context.token = context.token.replaceAll('"','"');
138 | context.token = context.token.replaceAll(''',"'");
139 | context.token = context.token.replaceAll('>','>');
140 | context.token = context.token.replaceAll('<','<');
141 | if (context.token.indexOf('') >= 0) {
142 | context.token = context.token.replace(/&(?:#([0-9]+)|#x([0-9a-fA-F]+));/g, function(match, group1, group2) {
143 | var e;
144 | if (group2) {
145 | e = String.fromCharCode(parseInt(group2,16));
146 | if ((e.charCodeAt(0) < 32) && (context.validControlChars.indexOf(e) < 0)) {
147 | context.newState = context.state = sError;
148 | }
149 | return e;
150 | }
151 | else {
152 | e = String.fromCharCode(group1);
153 | if ((e.charCodeAt(0) < 32) && (context.validControlChars.indexOf(e) < 0)) {
154 | context.newState = context.state = sError;
155 | }
156 | return e;
157 | }
158 | });
159 | }
160 | }
161 |
162 | if (context.state == sElement) context.depth++;
163 | else if (context.state == sEndElement) {
164 | context.depth--;
165 | if (context.depth<0) {
166 | context.newState = context.state = sError;
167 | }
168 | }
169 | if (context.state == sError) {
170 | context.error = true;
171 | }
172 | if (callback) {
173 | callback(context.state,context.token);
174 | }
175 | if (context.state == sError) {
176 | context.boundary = [];
177 | }
178 | }
179 |
180 | if (context.state == sInitial) {
181 | if (context.boundary[context.bIndex] == '') {
182 | context.newState = sDeclaration;
183 | context.boundary = ['?>'];
184 | }
185 | else {
186 | context.newState = sElement;
187 | context.boundary = ['>',' ','/','!--','?','!DOCTYPE','![CDATA['];
188 | context.boundary = context.boundary.concat(context.validControlChars);
189 | }
190 | }
191 | else if (context.state == sDeclaration) {
192 | context.newState = sPreElement;
193 | context.boundary = ['<'];
194 | if (context.token.indexOf('1.1')>0) {
195 | context.validControlChars.push('\u2028','\u0085','\u0015');
196 | }
197 | }
198 | else if (context.state == sPreElement) {
199 | context.newState = sElement;
200 | context.boundary = ['>',' ','/','!--','?','!DOCTYPE','![CDATA['];
201 | context.boundary = context.boundary.concat(context.validControlChars);
202 | }
203 | else if (context.state == sElement) {
204 | context.lastElement = context.token;
205 | if (c == '>') {
206 | context.newState = sContent;
207 | context.boundary = [''];
212 | }
213 | else if (c == '/') {
214 | context.newState = sEndElement;
215 | context.boundary = ['>'];
216 | context.keepToken = true;
217 | }
218 | else if (c == '?') {
219 | context.newState = sProcessingInstruction;
220 | context.boundary = ['?>'];
221 | }
222 | else if (context.boundary[context.bIndex] == '!--') {
223 | context.newState = sComment;
224 | context.boundary = ['-->'];
225 | }
226 | else if (context.boundary[context.bIndex] == '![CDATA[') {
227 | context.newState = sCData;
228 | context.boundary = [']]>'];
229 | }
230 | else if (context.boundary[context.bIndex] == '!DOCTYPE') {
231 | context.newState = sDocType;
232 | context.boundary = ['>','['];
233 | }
234 | }
235 | else if (context.state == sAttribute) {
236 | if (c == '=' ) {
237 | context.newState = sAttrNML;
238 | context.boundary = ['\'','"'];
239 | }
240 | else if (c == '>') {
241 | context.newState = sContent;
242 | context.boundary = [''];
258 | }
259 | else if (context.state == sEndElement) {
260 | if (context.depth !== 0) context.newState = sContent;
261 | context.boundary = ['<']; // don't allow DOCTYPE's after the first sEndElement
262 | }
263 | else if (context.state == sContent) {
264 | if (context.boundary[context.bIndex] == '','['];
267 | }
268 | else {
269 | context.newState = sElement;
270 | context.boundary = ['>',' ','/','!--','?','![CDATA['];
271 | context.boundary = context.boundary.concat(context.validControlChars);
272 | }
273 | }
274 | else if (context.state == sComment) {
275 | context.newState = sContent;
276 | context.boundary = [''];
290 | }
291 | else {
292 | context.newState = sPreElement;
293 | context.boundary = ['<'];
294 | }
295 | }
296 | else if (context.state == sDTD) {
297 | context.newState = sPreElement;
298 | context.boundary = ['<'];
299 | }
300 |
301 | if (!callback) {
302 | if (((context.state & 1) == 1) && ((context.token.trim() !== '') || context.state == sValue)) {
303 | context.position = i+1;
304 | return context;
305 | }
306 | }
307 | context.state = context.newState;
308 |
309 | if (!context.keepToken) context.token = '';
310 | }
311 | else {
312 | context.token += c;
313 | }
314 |
315 | }
316 | if ((context.state == sEndElement) && (context.depth === 0) && (context.token.trim() === '')) {
317 | context.wellFormed = true;
318 | }
319 | if ((!context.wellFormed) && (!context.error)) {
320 | if (callback) {
321 | // generate a final error, only for pushparsers though
322 | callback(sError,context.token);
323 | }
324 | }
325 | context.state = sEndDocument;
326 | if (callback) {
327 | callback(context.state,context.token);
328 | return context.wellFormed;
329 | }
330 | else {
331 | return context;
332 | }
333 | }
334 |
335 | module.exports = {
336 | parse : jgeParse,
337 | getStateName : stateName,
338 | sInitial : sInitial,
339 | sDeclaration : sDeclaration,
340 | sElement : sElement,
341 | sAttribute : sAttribute,
342 | sValue : sValue,
343 | sEndElement : sEndElement,
344 | sContent : sContent,
345 | sComment : sComment,
346 | sProcessingInstruction: sProcessingInstruction,
347 | sCData : sCData,
348 | sDocType : sDocType,
349 | sDTD : sDTD,
350 | sEndDocument : sEndDocument
351 | };
352 |
--------------------------------------------------------------------------------
/test/c4atom_noap.coerceTypes.xml:
--------------------------------------------------------------------------------
1 |
2 | tag:www.channel4.com,2009:/coming-soon
3 | Coming Soon to TV
4 | 2016-06-30T14:03:48.095Z
5 |
6 | Channel 4 Television
7 |
8 | http://ic.c4assets.com/c4_atom_small.gif?interpolation=none&resize=86px:63px
9 |
10 | 1.1
11 | PMLSD
12 |
13 | tag:www.channel4.com,2009:slot/29241908
14 | Ramsay's Hotel Hell
15 | Gordon Ramsay returns to the USA to help Angler's Lodge in Idaho, a stunning venue whose owners have been struck by family tragedy. Can Gordon rescue the broken family's business?
16 | 2016-06-30T14:03:50.140Z
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Ramsay's Hotel Hell
26 | 3
27 | 1
28 | 2016-06-30T21:00:00.000Z
29 | C4
30 | true
31 | true
32 | 60:00
33 | false
34 | false
35 | false
36 | 64418/001
37 | ramsays-hotel-hell
38 | false
39 | MST
40 | true
41 | true
42 | Gordon Ramsay helps hopeless hotels in the US
43 |
44 |
45 | tag:www.channel4.com,2009:slot/29243148
46 | Gogglebox
47 | A special programme revisiting some of the best and funniest moments from the most recent series, from Britain's Got Talent to First Dates, Caravanner of the Year and Dogs Might Fly.
48 | 2016-06-30T14:03:50.142Z
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | Gogglebox
59 | 2016
60 | 1
61 | 2016-07-01T20:00:00.000Z
62 | C4
63 | true
64 | true
65 | 60:00
66 | false
67 | false
68 | false
69 | 64702/001
70 | gogglebox
71 | false
72 | MSU
73 | true
74 | true
75 | What do Britain's favourite opinionated TV viewers think of our biggest programmes?
76 |
77 |
78 | tag:www.channel4.com,2009:slot/29243196
79 | China's Forgotten Emperor
80 | For 1300 years Wu Zetian, China's only female Emperor, has been remembered as a callous tyrant who brought calamity to China. But new discoveries reveal a very different story of her reign.
81 | 2016-06-30T14:03:50.143Z
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | China's Forgotten Emperor
90 | 1
91 | 1
92 | 2016-07-03T19:00:00.000Z
93 | C4
94 | true
95 | true
96 | 60:00
97 | false
98 | false
99 | false
100 | 62159/001
101 | chinas-forgotten-emperor
102 | false
103 | OOS
104 | true
105 | true
106 | Recent discoveries are casting new light on the reign of China's only female Emperor
107 |
108 |
109 | tag:www.channel4.com,2009:slot/29243771
110 | 999: What's Your Emergency?
111 | The new series focuses on the work of Cheshire's emergency services. When a 20-year-old girl collapses at home after a night out, her life depends on Will, at the 999 call centre. (S3 Ep1)
112 | 2016-06-30T14:03:50.145Z
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | 999: What's Your Emergency?
123 | 3
124 | 1
125 | 2016-07-04T20:00:00.000Z
126 | C4
127 | true
128 | false
129 | 60:00
130 | false
131 | false
132 | false
133 | 59274/001
134 | 999-whats-your-emergency
135 | false
136 | MSU
137 | true
138 | true
139 | An intimate and frank look at modern Britain through the eyes of the emergency services
140 |
141 |
142 |
--------------------------------------------------------------------------------
/out/c4atom_noap.coerceTypes.json:
--------------------------------------------------------------------------------
1 | {
2 | "feed": {
3 | "xmlns": "http://www.w3.org/2005/Atom",
4 | "xmlns:dc": "http://purl.org/dc/elements/1.1/",
5 | "xmlns:media": "http://search.yahoo.com/mrss/",
6 | "xmlns:dcterms": "http://purl.org/dc/terms",
7 | "xml:base": "http://www.channel4.com",
8 | "id": "tag:www.channel4.com,2009:/coming-soon",
9 | "title": {
10 | "type": "text",
11 | "#text": "Coming Soon to TV"
12 | },
13 | "updated": "2016-06-30T14:03:48.095Z",
14 | "author": {
15 | "name": "Channel 4 Television"
16 | },
17 | "logo": {
18 | "imageSource": "default",
19 | "#text": "http://ic.c4assets.com/c4_atom_small.gif?interpolation=none&resize=86px:63px"
20 | },
21 | "link": {
22 | "rel": "self",
23 | "href": "http://api.channel4.com/pmlsd/coming-soon.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
24 | "type": "application/atom+xml"
25 | },
26 | "dc:relation.platformClientVersion": 1.1,
27 | "generator": {
28 | "version": 2.14,
29 | "#text": "PMLSD"
30 | },
31 | "entry": [
32 | {
33 | "id": "tag:www.channel4.com,2009:slot/29241908",
34 | "title": {
35 | "type": "text",
36 | "#text": "Ramsay's Hotel Hell"
37 | },
38 | "summary": {
39 | "type": "text",
40 | "#text": "Gordon Ramsay returns to the USA to help Angler's Lodge in Idaho, a stunning venue whose owners have been struck by family tragedy. Can Gordon rescue the broken family's business?"
41 | },
42 | "updated": "2016-06-30T14:03:50.140Z",
43 | "link": [
44 | {
45 | "rel": "alternate",
46 | "href": "http://www.channel4.com/programmes/ramsays-hotel-hell",
47 | "type": "text/html"
48 | },
49 | {
50 | "rel": "self",
51 | "href": "http://api.channel4.com/pmlsd/ramsays-hotel-hell.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
52 | "type": "application/atom+xml"
53 | },
54 | {
55 | "rel": "related",
56 | "href": "http://api.channel4.com/pmlsd/ramsays-hotel-hell/4od.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
57 | "type": "application/atom+xml",
58 | "title": "4oD"
59 | },
60 | {
61 | "rel": "related",
62 | "href": "http://api.channel4.com/pmlsd/ramsays-hotel-hell/4od/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
63 | "type": "application/atom+xml",
64 | "title": "4oD Episode Guide"
65 | },
66 | {
67 | "rel": "related",
68 | "href": "http://api.channel4.com/pmlsd/ramsays-hotel-hell/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
69 | "type": "application/atom+xml",
70 | "title": "Episode Guide"
71 | }
72 | ],
73 | "media:content": {
74 | "media:thumbnail": {
75 | "imageSource": "own",
76 | "altText": "Ramsay's Hotel Hell",
77 | "width": 200,
78 | "url": "http://cache.channel4.com/assets/programmes/images/ramsays-hotel-hell/series-3/episode-1/9aab52d1-3208-4ed8-b2ad-a11239c484eb_200x113.jpg",
79 | "height": 113
80 | }
81 | },
82 | "dc:relation.BrandTitle": "Ramsay's Hotel Hell",
83 | "dc:relation.SeriesNumber": 3,
84 | "dc:relation.EpisodeNumber": 1,
85 | "dc:date.TXDate": "2016-06-30T21:00:00.000Z",
86 | "dc:relation.TXChannel": "C4",
87 | "dc:relation.Subtitles": true,
88 | "dc:relation.AudioDescription": true,
89 | "dc:relation.Duration": "60:00",
90 | "dc:relation.WideScreen": false,
91 | "dc:relation.Signing": false,
92 | "dc:relation.Repeat": false,
93 | "dc:relation.programmeId": "64418/001",
94 | "dc:relation.BrandWebSafeTitle": "ramsays-hotel-hell",
95 | "dc:relation.Movie": false,
96 | "dc:relation.ProgrammeType": "MST",
97 | "dc:relation.SimulcastRights": true,
98 | "dc:relation.hd": true,
99 | "dc:relation.ShortSynopsis": "Gordon Ramsay helps hopeless hotels in the US"
100 | },
101 | {
102 | "id": "tag:www.channel4.com,2009:slot/29243148",
103 | "title": {
104 | "type": "text",
105 | "#text": "Gogglebox"
106 | },
107 | "summary": {
108 | "type": "text",
109 | "#text": "A special programme revisiting some of the best and funniest moments from the most recent series, from Britain's Got Talent to First Dates, Caravanner of the Year and Dogs Might Fly."
110 | },
111 | "updated": "2016-06-30T14:03:50.142Z",
112 | "link": [
113 | {
114 | "rel": "alternate",
115 | "href": "http://www.channel4.com/programmes/gogglebox",
116 | "type": "text/html"
117 | },
118 | {
119 | "rel": "self",
120 | "href": "http://api.channel4.com/pmlsd/gogglebox.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
121 | "type": "application/atom+xml"
122 | },
123 | {
124 | "rel": "related",
125 | "href": "http://api.channel4.com/pmlsd/gogglebox/4od.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
126 | "type": "application/atom+xml",
127 | "title": "4oD"
128 | },
129 | {
130 | "rel": "related",
131 | "href": "http://api.channel4.com/pmlsd/gogglebox/4od/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
132 | "type": "application/atom+xml",
133 | "title": "4oD Episode Guide"
134 | },
135 | {
136 | "rel": "related",
137 | "href": "http://api.channel4.com/pmlsd/gogglebox/videos/all.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
138 | "type": "application/atom+xml",
139 | "title": "Clips"
140 | },
141 | {
142 | "rel": "related",
143 | "href": "http://api.channel4.com/pmlsd/gogglebox/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
144 | "type": "application/atom+xml",
145 | "title": "Episode Guide"
146 | }
147 | ],
148 | "media:content": {
149 | "media:thumbnail": {
150 | "imageSource": "fallback",
151 | "altText": "Gogglebox: The Best Bits",
152 | "width": 200,
153 | "url": "http://cache.channel4.com/assets/programmes/images/gogglebox/series-2016/b944a7f5-7d23-4c4e-825f-893a27d43640_200x113.jpg",
154 | "height": 113
155 | }
156 | },
157 | "dc:relation.BrandTitle": "Gogglebox",
158 | "dc:relation.SeriesNumber": 2016,
159 | "dc:relation.EpisodeNumber": 1,
160 | "dc:date.TXDate": "2016-07-01T20:00:00.000Z",
161 | "dc:relation.TXChannel": "C4",
162 | "dc:relation.Subtitles": true,
163 | "dc:relation.AudioDescription": true,
164 | "dc:relation.Duration": "60:00",
165 | "dc:relation.WideScreen": false,
166 | "dc:relation.Signing": false,
167 | "dc:relation.Repeat": false,
168 | "dc:relation.programmeId": "64702/001",
169 | "dc:relation.BrandWebSafeTitle": "gogglebox",
170 | "dc:relation.Movie": false,
171 | "dc:relation.ProgrammeType": "MSU",
172 | "dc:relation.SimulcastRights": true,
173 | "dc:relation.hd": true,
174 | "dc:relation.ShortSynopsis": "What do Britain's favourite opinionated TV viewers think of our biggest programmes?"
175 | },
176 | {
177 | "id": "tag:www.channel4.com,2009:slot/29243196",
178 | "title": {
179 | "type": "text",
180 | "#text": "China's Forgotten Emperor"
181 | },
182 | "summary": {
183 | "type": "text",
184 | "#text": "For 1300 years Wu Zetian, China's only female Emperor, has been remembered as a callous tyrant who brought calamity to China. But new discoveries reveal a very different story of her reign."
185 | },
186 | "updated": "2016-06-30T14:03:50.143Z",
187 | "link": [
188 | {
189 | "rel": "alternate",
190 | "href": "http://www.channel4.com/programmes/chinas-forgotten-emperor",
191 | "type": "text/html"
192 | },
193 | {
194 | "rel": "self",
195 | "href": "http://api.channel4.com/pmlsd/chinas-forgotten-emperor.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
196 | "type": "application/atom+xml"
197 | },
198 | {
199 | "rel": "related",
200 | "href": "http://api.channel4.com/pmlsd/chinas-forgotten-emperor/videos/all.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
201 | "type": "application/atom+xml",
202 | "title": "Clips"
203 | },
204 | {
205 | "rel": "related",
206 | "href": "http://api.channel4.com/pmlsd/chinas-forgotten-emperor/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
207 | "type": "application/atom+xml",
208 | "title": "Episode Guide"
209 | }
210 | ],
211 | "media:content": {
212 | "media:thumbnail": {
213 | "imageSource": "fallback",
214 | "altText": "China's Forgotten Emperor",
215 | "width": 200,
216 | "url": "http://cache.channel4.com/assets/programmes/images/chinas-forgotten-emperor/series-1/9fe59fef-180b-46ed-9a71-31ac09dc5d9d_200x113.jpg",
217 | "height": 113
218 | }
219 | },
220 | "dc:relation.BrandTitle": "China's Forgotten Emperor",
221 | "dc:relation.SeriesNumber": 1,
222 | "dc:relation.EpisodeNumber": 1,
223 | "dc:date.TXDate": "2016-07-03T19:00:00.000Z",
224 | "dc:relation.TXChannel": "C4",
225 | "dc:relation.Subtitles": true,
226 | "dc:relation.AudioDescription": true,
227 | "dc:relation.Duration": "60:00",
228 | "dc:relation.WideScreen": false,
229 | "dc:relation.Signing": false,
230 | "dc:relation.Repeat": false,
231 | "dc:relation.programmeId": "62159/001",
232 | "dc:relation.BrandWebSafeTitle": "chinas-forgotten-emperor",
233 | "dc:relation.Movie": false,
234 | "dc:relation.ProgrammeType": "OOS",
235 | "dc:relation.SimulcastRights": true,
236 | "dc:relation.hd": true,
237 | "dc:relation.ShortSynopsis": "Recent discoveries are casting new light on the reign of China's only female Emperor"
238 | },
239 | {
240 | "id": "tag:www.channel4.com,2009:slot/29243771",
241 | "title": {
242 | "type": "text",
243 | "#text": "999: What's Your Emergency?"
244 | },
245 | "summary": {
246 | "type": "text",
247 | "#text": "The new series focuses on the work of Cheshire's emergency services. When a 20-year-old girl collapses at home after a night out, her life depends on Will, at the 999 call centre. (S3 Ep1)"
248 | },
249 | "updated": "2016-06-30T14:03:50.145Z",
250 | "link": [
251 | {
252 | "rel": "alternate",
253 | "href": "http://www.channel4.com/programmes/999-whats-your-emergency",
254 | "type": "text/html"
255 | },
256 | {
257 | "rel": "self",
258 | "href": "http://api.channel4.com/pmlsd/999-whats-your-emergency.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
259 | "type": "application/atom+xml"
260 | },
261 | {
262 | "rel": "related",
263 | "href": "http://api.channel4.com/pmlsd/999-whats-your-emergency/4od.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
264 | "type": "application/atom+xml",
265 | "title": "4oD"
266 | },
267 | {
268 | "rel": "related",
269 | "href": "http://api.channel4.com/pmlsd/999-whats-your-emergency/4od/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
270 | "type": "application/atom+xml",
271 | "title": "4oD Episode Guide"
272 | },
273 | {
274 | "rel": "related",
275 | "href": "http://api.channel4.com/pmlsd/999-whats-your-emergency/videos/all.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
276 | "type": "application/atom+xml",
277 | "title": "Clips"
278 | },
279 | {
280 | "rel": "related",
281 | "href": "http://api.channel4.com/pmlsd/999-whats-your-emergency/episode-guide.atom?apikey=xxxxxxxxxxxxxxxxxxxxxxx",
282 | "type": "application/atom+xml",
283 | "title": "Episode Guide"
284 | }
285 | ],
286 | "media:content": {
287 | "media:thumbnail": {
288 | "imageSource": "own",
289 | "altText": "999: What's Your Emergency?",
290 | "width": 200,
291 | "url": "http://cache.channel4.com/assets/programmes/images/999-whats-your-emergency/series-3/episode-1/1bdb70dd-6934-41f2-9c80-620eb83e082b_200x113.jpg",
292 | "height": 113
293 | }
294 | },
295 | "dc:relation.BrandTitle": "999: What's Your Emergency?",
296 | "dc:relation.SeriesNumber": 3,
297 | "dc:relation.EpisodeNumber": 1,
298 | "dc:date.TXDate": "2016-07-04T20:00:00.000Z",
299 | "dc:relation.TXChannel": "C4",
300 | "dc:relation.Subtitles": true,
301 | "dc:relation.AudioDescription": false,
302 | "dc:relation.Duration": "60:00",
303 | "dc:relation.WideScreen": false,
304 | "dc:relation.Signing": false,
305 | "dc:relation.Repeat": false,
306 | "dc:relation.programmeId": "59274/001",
307 | "dc:relation.BrandWebSafeTitle": "999-whats-your-emergency",
308 | "dc:relation.Movie": false,
309 | "dc:relation.ProgrammeType": "MSU",
310 | "dc:relation.SimulcastRights": true,
311 | "dc:relation.hd": true,
312 | "dc:relation.ShortSynopsis": "An intimate and frank look at modern Britain through the eyes of the emergency services"
313 | }
314 | ]
315 | }
316 | }
317 |
--------------------------------------------------------------------------------
/test/atomSchema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | This version of the Atom schema is based on version 1.0 of the format specifications, found here http://www.atomenabled.org/developers/syndication/atom-format-spec.php. The original namespace was http://www.w3.org/2005/Atom but we changed it to http://www.opengis.net/atom/2005 to avoid conflicting definitions of the same namespace in the future. NOT DONE YET. There is no XSD official schema for atom but this one seems to be the most known: http://www.kbcafe.com/rss/atom.xsd.xml (The Atom Publishing Protocol was issued as a Proposed Standard in IETF RFC 5023 in October 2007 http://tools.ietf.org/html/rfc5023)
6 |
7 |
8 |
9 |
10 |
11 | An Atom document may have two root elements, feed and entry, as defined in section 2.
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | XML encoded identifier of a standard MIME type, possibly a parameterized MIME type. Copied from ows 2.0.1
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | The Atom text construct is defined in section 3.1 of the format spec.
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | The Atom person construct is defined in section 3.2 of the format spec.
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | Schema definition for an email address.
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | The Atom feed construct is defined in section 4.1.1 of the format spec.
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | The Atom entry construct is defined in section 4.1.2 of the format spec.
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | The Atom content construct is defined in section 4.1.3 of the format spec.
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 | The Atom category construct is defined in section 4.2.2 of the format spec.
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | The Atom generator element is defined in section 4.2.4 of the format spec.
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | The Atom icon construct is defined in section 4.2.5 of the format spec.
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | The Atom id construct is defined in section 4.2.6 of the format spec.
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 | The value "alternate" signifies that the IRI in the value of the href attribute identifies an alternate version of the resource described by the containing element.
185 |
186 |
187 |
188 |
189 |
190 |
191 | The value "related" signifies that the IRI in the value of the href attribute identifies a resource related to the resource described by the containing element. For example, the feed for a site that discusses the performance of the search engine at "http://search.example.com" might contain, as a child of atom:feed. An identical link might appear as a child of any atom:entry whose content contains a discussion of that same search engine.
192 |
193 |
194 |
195 |
196 |
197 |
198 | The value "self" signifies that the IRI in the value of the href attribute identifies a resource equivalent to the containing element.
199 |
200 |
201 |
202 |
203 |
204 |
205 | The value "enclosure" signifies that the IRI in the value of the href attribute identifies a related resource that is potentially large in size and might require special handling. For atom:link elements with rel="enclosure", the length attribute SHOULD be provided.
206 |
207 |
208 |
209 |
210 |
211 |
212 | The value "via" signifies that the IRI in the value of the href attribute identifies a resource that is the source of the information provided in the containing element.
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 | The Atom link construct is defined in section 3.4 of the format spec.
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 | The Atom logo construct is defined in section 4.2.8 of the format spec.
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 | The Atom source construct is defined in section 4.2.11 of the format spec.
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
--------------------------------------------------------------------------------
/out/atomSchema.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "test/atomSchema.xsd",
3 | "$schema": "http://json-schema.org/schema#",
4 | "id": "http://www.w3.org/2005/Atom",
5 | "description": "This version of the Atom schema is based on version 1.0 of the format specifications, found here http://www.atomenabled.org/developers/syndication/atom-format-spec.php. The original namespace was http://www.w3.org/2005/Atom but we changed it to http://www.opengis.net/atom/2005 to avoid conflicting definitions of the same namespace in the future. NOT DONE YET. There is no XSD official schema for atom but this one seems to be the most known: http://www.kbcafe.com/rss/atom.xsd.xml (The Atom Publishing Protocol was issued as a Proposed Standard in IETF RFC 5023 in October 2007 http://tools.ietf.org/html/rfc5023)\nAn Atom document may have two root elements, feed and entry, as defined in section 2.",
6 | "type": "object",
7 | "properties": {
8 | "feed": {
9 | "$ref": "#/definitions/feedType"
10 | }
11 | },
12 | "required": [
13 | "feed"
14 | ],
15 | "additionalProperties": false,
16 | "definitions": {
17 | "entry": {
18 | "$ref": "#/definitions/entryType"
19 | },
20 | "textTypeType": {
21 | "type": "string",
22 | "enum": [
23 | "text",
24 | "html",
25 | "xhtml"
26 | ]
27 | },
28 | "MimeType": {
29 | "type": "string",
30 | "description": "XML encoded identifier of a standard MIME type, possibly a parameterized MIME type. Copied from ows 2.0.1",
31 | "pattern": "(application|audio|image|text|video|message|multipart|model)/.+(;\\s*.+=.+)*"
32 | },
33 | "ContentTypeType": {
34 | "type": "object",
35 | "oneOf": [
36 | {
37 | "$ref": "#/definitions/textTypeType"
38 | },
39 | {
40 | "$ref": "#/definitions/MimeType"
41 | }
42 | ],
43 | "additionalProperties": false
44 | },
45 | "emailType": {
46 | "type": "string",
47 | "description": "Schema definition for an email address.",
48 | "pattern": "\\w+@(\\w+\\.)+\\w+"
49 | },
50 | "KnownRelCodeType": {
51 | "type": "string",
52 | "description": "alternate: The value \"alternate\" signifies that the IRI in the value of the href attribute identifies an alternate version of the resource described by the containing element.related: The value \"related\" signifies that the IRI in the value of the href attribute identifies a resource related to the resource described by the containing element. For example, the feed for a site that discusses the performance of the search engine at \"http://search.example.com\" might contain, as a child of atom:feed. An identical link might appear as a child of any atom:entry whose content contains a discussion of that same search engine.self: The value \"self\" signifies that the IRI in the value of the href attribute identifies a resource equivalent to the containing element.enclosure: The value \"enclosure\" signifies that the IRI in the value of the href attribute identifies a related resource that is potentially large in size and might require special handling. For atom:link elements with rel=\"enclosure\", the length attribute SHOULD be provided.via: The value \"via\" signifies that the IRI in the value of the href attribute identifies a resource that is the source of the information provided in the containing element.",
53 | "enum": [
54 | "alternate",
55 | "related",
56 | "self",
57 | "enclosure",
58 | "via"
59 | ]
60 | },
61 | "RelCodeType": {
62 | "type": "object",
63 | "oneOf": [
64 | {
65 | "$ref": "#/definitions/KnownRelCodeType"
66 | },
67 | {
68 | "type": "string"
69 | }
70 | ],
71 | "additionalProperties": false
72 | },
73 | "textType": {
74 | "type": "object",
75 | "description": "The Atom text construct is defined in section 3.1 of the format spec.",
76 | "additionalProperties": true,
77 | "anyOf": [
78 | {
79 | "$ref": "#/definitions/commonAttributes"
80 | },
81 | {
82 | "properties": {
83 | "type": {
84 | "$ref": "#/definitions/textTypeType"
85 | }
86 | }
87 | }
88 | ]
89 | },
90 | "personType": {
91 | "type": "object",
92 | "description": "The Atom person construct is defined in section 3.2 of the format spec.",
93 | "additionalProperties": true,
94 | "anyOf": [
95 | {
96 | "$ref": "#/definitions/commonAttributes"
97 | },
98 | {
99 | "properties": {
100 | "name": {
101 | "type": "string"
102 | },
103 | "uri": {
104 | "$ref": "#/definitions/uriType"
105 | },
106 | "email": {
107 | "$ref": "#/definitions/emailType"
108 | }
109 | }
110 | }
111 | ]
112 | },
113 | "feedType": {
114 | "type": "object",
115 | "description": "The Atom feed construct is defined in section 4.1.1 of the format spec.",
116 | "additionalProperties": true,
117 | "anyOf": [
118 | {
119 | "$ref": "#/definitions/commonAttributes"
120 | },
121 | {
122 | "properties": {
123 | "author": {
124 | "type": "array",
125 | "items": {
126 | "$ref": "#/definitions/personType"
127 | }
128 | },
129 | "category": {
130 | "type": "array",
131 | "items": {
132 | "$ref": "#/definitions/categoryType"
133 | }
134 | },
135 | "contributor": {
136 | "type": "array",
137 | "items": {
138 | "$ref": "#/definitions/personType"
139 | }
140 | },
141 | "generator": {
142 | "$ref": "#/definitions/generatorType"
143 | },
144 | "icon": {
145 | "$ref": "#/definitions/iconType"
146 | },
147 | "id": {
148 | "$ref": "#/definitions/idType"
149 | },
150 | "link": {
151 | "type": "array",
152 | "items": {
153 | "$ref": "#/definitions/linkType"
154 | }
155 | },
156 | "logo": {
157 | "$ref": "#/definitions/logoType"
158 | },
159 | "rights": {
160 | "$ref": "#/definitions/textType"
161 | },
162 | "subtitle": {
163 | "$ref": "#/definitions/textType"
164 | },
165 | "title": {
166 | "$ref": "#/definitions/textType"
167 | },
168 | "updated": {
169 | "$ref": "#/definitions/dateTimeType"
170 | },
171 | "entry": {
172 | "type": "array",
173 | "items": {
174 | "$ref": "#/definitions/entryType"
175 | }
176 | }
177 | }
178 | }
179 | ]
180 | },
181 | "entryType": {
182 | "type": "object",
183 | "description": "The Atom entry construct is defined in section 4.1.2 of the format spec.",
184 | "additionalProperties": true,
185 | "anyOf": [
186 | {
187 | "$ref": "#/definitions/commonAttributes"
188 | },
189 | {
190 | "properties": {
191 | "author": {
192 | "type": "array",
193 | "items": {
194 | "$ref": "#/definitions/personType"
195 | }
196 | },
197 | "category": {
198 | "type": "array",
199 | "items": {
200 | "$ref": "#/definitions/categoryType"
201 | }
202 | },
203 | "content": {
204 | "$ref": "#/definitions/contentType"
205 | },
206 | "contributor": {
207 | "type": "array",
208 | "items": {
209 | "$ref": "#/definitions/personType"
210 | }
211 | },
212 | "id": {
213 | "$ref": "#/definitions/idType"
214 | },
215 | "link": {
216 | "type": "array",
217 | "items": {
218 | "$ref": "#/definitions/linkType"
219 | }
220 | },
221 | "published": {
222 | "$ref": "#/definitions/dateTimeType"
223 | },
224 | "rights": {
225 | "$ref": "#/definitions/textType"
226 | },
227 | "source": {
228 | "$ref": "#/definitions/textType"
229 | },
230 | "summary": {
231 | "$ref": "#/definitions/textType"
232 | },
233 | "title": {
234 | "$ref": "#/definitions/textType"
235 | },
236 | "updated": {
237 | "$ref": "#/definitions/dateTimeType"
238 | }
239 | }
240 | }
241 | ]
242 | },
243 | "contentType": {
244 | "type": "object",
245 | "description": "The Atom content construct is defined in section 4.1.3 of the format spec.",
246 | "additionalProperties": true,
247 | "anyOf": [
248 | {
249 | "$ref": "#/definitions/commonAttributes"
250 | },
251 | {
252 | "properties": {
253 | "type": {
254 | "$ref": "#/definitions/ContentTypeType"
255 | },
256 | "src": {
257 | "type": "string",
258 | "format": "uri"
259 | }
260 | }
261 | }
262 | ]
263 | },
264 | "categoryType": {
265 | "type": "object",
266 | "description": "The Atom category construct is defined in section 4.2.2 of the format spec.",
267 | "additionalProperties": false,
268 | "anyOf": [
269 | {
270 | "required": [
271 | "term"
272 | ],
273 | "$ref": "#/definitions/commonAttributes"
274 | },
275 | {
276 | "properties": {
277 | "term": {
278 | "type": "string"
279 | },
280 | "scheme": {
281 | "type": "string",
282 | "format": "uri"
283 | },
284 | "label": {
285 | "type": "string"
286 | }
287 | }
288 | }
289 | ]
290 | },
291 | "generatorType": {
292 | "type": "object",
293 | "description": "The Atom generator element is defined in section 4.2.4 of the format spec.",
294 | "additionalProperties": false,
295 | "anyOf": [
296 | {
297 | "$ref": "#/definitions/commonAttributes"
298 | },
299 | {
300 | "properties": {
301 | "uri": {
302 | "type": "string",
303 | "format": "uri"
304 | },
305 | "version": {
306 | "type": "string"
307 | },
308 | "#text": {
309 | "type": "string"
310 | }
311 | }
312 | }
313 | ]
314 | },
315 | "iconType": {
316 | "type": "object",
317 | "description": "The Atom icon construct is defined in section 4.2.5 of the format spec.",
318 | "additionalProperties": false,
319 | "anyOf": [
320 | {
321 | "$ref": "#/definitions/commonAttributes"
322 | },
323 | {
324 | "properties": {
325 | "#text": {
326 | "type": "string",
327 | "format": "uri"
328 | }
329 | }
330 | }
331 | ]
332 | },
333 | "idType": {
334 | "type": "object",
335 | "description": "The Atom id construct is defined in section 4.2.6 of the format spec.",
336 | "additionalProperties": false,
337 | "anyOf": [
338 | {
339 | "$ref": "#/definitions/commonAttributes"
340 | },
341 | {
342 | "properties": {
343 | "#text": {
344 | "type": "string",
345 | "format": "uri"
346 | }
347 | }
348 | }
349 | ]
350 | },
351 | "linkType": {
352 | "type": "object",
353 | "description": "The Atom link construct is defined in section 3.4 of the format spec.",
354 | "additionalProperties": false,
355 | "anyOf": [
356 | {
357 | "required": [
358 | "href"
359 | ],
360 | "$ref": "#/definitions/commonAttributes"
361 | },
362 | {
363 | "properties": {
364 | "href": {
365 | "type": "string",
366 | "format": "uri"
367 | },
368 | "rel": {
369 | "$ref": "#/definitions/RelCodeType"
370 | },
371 | "type": {
372 | "type": "string"
373 | },
374 | "hreflang": {
375 | "type": "string"
376 | },
377 | "title": {
378 | "type": "string"
379 | },
380 | "length": {
381 | "type": "integer",
382 | "minimum": 1
383 | }
384 | }
385 | }
386 | ]
387 | },
388 | "logoType": {
389 | "type": "object",
390 | "description": "The Atom logo construct is defined in section 4.2.8 of the format spec.",
391 | "additionalProperties": false,
392 | "anyOf": [
393 | {
394 | "$ref": "#/definitions/commonAttributes"
395 | },
396 | {
397 | "properties": {
398 | "#text": {
399 | "type": "string",
400 | "format": "uri"
401 | }
402 | }
403 | }
404 | ]
405 | },
406 | "sourceType": {
407 | "type": "object",
408 | "description": "The Atom source construct is defined in section 4.2.11 of the format spec.",
409 | "additionalProperties": true,
410 | "anyOf": [
411 | {
412 | "$ref": "#/definitions/commonAttributes"
413 | },
414 | {
415 | "properties": {
416 | "author": {
417 | "type": "array",
418 | "items": {
419 | "$ref": "#/definitions/personType"
420 | }
421 | },
422 | "category": {
423 | "type": "array",
424 | "items": {
425 | "$ref": "#/definitions/categoryType"
426 | }
427 | },
428 | "contributor": {
429 | "type": "array",
430 | "items": {
431 | "$ref": "#/definitions/personType"
432 | }
433 | },
434 | "generator": {
435 | "$ref": "#/definitions/generatorType"
436 | },
437 | "icon": {
438 | "$ref": "#/definitions/iconType"
439 | },
440 | "id": {
441 | "$ref": "#/definitions/idType"
442 | },
443 | "link": {
444 | "type": "array",
445 | "items": {
446 | "$ref": "#/definitions/linkType"
447 | }
448 | },
449 | "logo": {
450 | "$ref": "#/definitions/logoType"
451 | },
452 | "rights": {
453 | "$ref": "#/definitions/textType"
454 | },
455 | "subtitle": {
456 | "$ref": "#/definitions/textType"
457 | },
458 | "title": {
459 | "$ref": "#/definitions/textType"
460 | },
461 | "updated": {
462 | "$ref": "#/definitions/dateTimeType"
463 | }
464 | }
465 | }
466 | ]
467 | },
468 | "uriType": {
469 | "type": "object",
470 | "additionalProperties": false,
471 | "anyOf": [
472 | {
473 | "$ref": "#/definitions/commonAttributes"
474 | },
475 | {
476 | "properties": {
477 | "#text": {
478 | "type": "string",
479 | "format": "uri"
480 | }
481 | }
482 | }
483 | ]
484 | },
485 | "dateTimeType": {
486 | "type": "object",
487 | "additionalProperties": false,
488 | "anyOf": [
489 | {
490 | "$ref": "#/definitions/commonAttributes"
491 | },
492 | {
493 | "properties": {
494 | "#text": {
495 | "type": "string",
496 | "format": "date-time"
497 | }
498 | }
499 | }
500 | ]
501 | },
502 | "commonAttributes": {
503 | "type": "object",
504 | "properties": {
505 | "xml:base": {
506 | "type": "string"
507 | },
508 | "xml:lang": {
509 | "type": "string"
510 | }
511 | },
512 | "additionalProperties": true
513 | }
514 | }
515 | }
516 |
--------------------------------------------------------------------------------
/test/mpd-dash.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Media Presentation Description
6 |
7 | This Schema defines the Media Presentation Description for MPEG-DASH.
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
--------------------------------------------------------------------------------