Skip to content
Snippets Groups Projects
Commit aa3a42f9 authored by Alexander Rose's avatar Alexander Rose
Browse files

added simple xml parser

parent 4bff55b6
No related branches found
No related tags found
No related merge requests found
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
import { Task, RuntimeContext } from '../mol-task'; import { Task, RuntimeContext } from '../mol-task';
import { utf8Read } from '../mol-io/common/utf8'; import { utf8Read } from '../mol-io/common/utf8';
import { parseXml } from './xml-parser';
// polyfill XMLHttpRequest in node.js // polyfill XMLHttpRequest in node.js
const XHR = typeof document === 'undefined' ? require('xhr2') as { const XHR = typeof document === 'undefined' ? require('xhr2') as {
prototype: XMLHttpRequest; prototype: XMLHttpRequest;
...@@ -25,7 +26,7 @@ const XHR = typeof document === 'undefined' ? require('xhr2') as { ...@@ -25,7 +26,7 @@ const XHR = typeof document === 'undefined' ? require('xhr2') as {
// Gzip // Gzip
// } // }
export interface AjaxGetParams<T extends 'string' | 'binary' | 'json' = 'string'> { export interface AjaxGetParams<T extends 'string' | 'binary' | 'json' | 'xml' = 'string'> {
url: string, url: string,
type?: T, type?: T,
title?: string, title?: string,
...@@ -49,10 +50,10 @@ export function readFromFile(file: File, type: 'string' | 'binary') { ...@@ -49,10 +50,10 @@ export function readFromFile(file: File, type: 'string' | 'binary') {
export function ajaxGet(url: string): Task<string> export function ajaxGet(url: string): Task<string>
export function ajaxGet(params: AjaxGetParams<'string'>): Task<string> export function ajaxGet(params: AjaxGetParams<'string'>): Task<string>
export function ajaxGet(params: AjaxGetParams<'binary'>): Task<Uint8Array> export function ajaxGet(params: AjaxGetParams<'binary'>): Task<Uint8Array>
export function ajaxGet<T = any>(params: AjaxGetParams<'json'>): Task<T> export function ajaxGet<T = any>(params: AjaxGetParams<'json' | 'xml'>): Task<T>
export function ajaxGet(params: AjaxGetParams<'string' | 'binary'>): Task<string | Uint8Array> export function ajaxGet(params: AjaxGetParams<'string' | 'binary'>): Task<string | Uint8Array>
export function ajaxGet(params: AjaxGetParams<'string' | 'binary' | 'json'>): Task<string | Uint8Array | object> export function ajaxGet(params: AjaxGetParams<'string' | 'binary' | 'json' | 'xml'>): Task<string | Uint8Array | object>
export function ajaxGet(params: AjaxGetParams<'string' | 'binary' | 'json'> | string) { export function ajaxGet(params: AjaxGetParams<'string' | 'binary' | 'json' | 'xml'> | string) {
if (typeof params === 'string') return ajaxGetInternal(params, params, 'string', false); if (typeof params === 'string') return ajaxGetInternal(params, params, 'string', false);
return ajaxGetInternal(params.title, params.url, params.type || 'string', false /* params.compression === DataCompressionMethod.Gzip */, params.body); return ajaxGetInternal(params.title, params.url, params.type || 'string', false /* params.compression === DataCompressionMethod.Gzip */, params.body);
} }
...@@ -174,7 +175,7 @@ async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompres ...@@ -174,7 +175,7 @@ async function processAjax(ctx: RuntimeContext, asUint8Array: boolean, decompres
} }
} }
function ajaxGetInternal(title: string | undefined, url: string, type: 'json' | 'string' | 'binary', decompressGzip: boolean, body?: string): Task<string | Uint8Array> { function ajaxGetInternal(title: string | undefined, url: string, type: 'json' | 'xml' | 'string' | 'binary', decompressGzip: boolean, body?: string): Task<string | Uint8Array> {
let xhttp: XMLHttpRequest | undefined = void 0; let xhttp: XMLHttpRequest | undefined = void 0;
return Task.create(title ? title : 'Download', async ctx => { return Task.create(title ? title : 'Download', async ctx => {
try { try {
...@@ -195,8 +196,10 @@ function ajaxGetInternal(title: string | undefined, url: string, type: 'json' | ...@@ -195,8 +196,10 @@ function ajaxGetInternal(title: string | undefined, url: string, type: 'json' |
if (type === 'json') { if (type === 'json') {
ctx.update({ message: 'Parsing JSON...', canAbort: false }); ctx.update({ message: 'Parsing JSON...', canAbort: false });
const data = JSON.parse(result); return JSON.parse(result);
return data; } else if (type === 'xml') {
ctx.update({ message: 'Parsing XML...', canAbort: false });
return parseXml(result);
} }
return result; return result;
......
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export type XMLNodeAttributes = { [k: string]: any }
export interface XMLNode {
name?: string
content?: string
attributes: XMLNodeAttributes
children?: XMLNode[]
}
export interface XMLDocument {
declaration?: XMLNode,
root?: XMLNode
}
export function getXMLNodeByName(name: string, children: XMLNode[]) {
for (let i = 0, il = children.length; i < il; ++i) {
if (children[i].name === name) return children[i]
}
}
const reStrip = /^['"]|['"]$/g
const reTag = /^<([\w-:.]+)\s*/
const reContent = /^([^<]*)/
const reAttr = /([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/
function strip (val: string) {
return val.replace(reStrip, '')
}
/**
* Simple XML parser
* adapted from https://github.com/segmentio/xml-parser (MIT license)
*/
export function parseXml (xml: string): XMLDocument {
// trim and strip comments
xml = xml.trim().replace(/<!--[\s\S]*?-->/g, '')
return document()
function document () {
return {
declaration: declaration(),
root: tag()
}
}
function declaration () {
const m = match(/^<\?xml\s*/)
if (!m) return
// tag
const node: XMLNode = {
attributes: {}
}
// attributes
while (!(eos() || is('?>'))) {
const attr = attribute()
if (!attr) return node
node.attributes[attr.name] = attr.value
}
match(/\?>\s*/)
return node
}
function tag () {
const m = match(reTag)
if (!m) return
// name
const node: XMLNode = {
name: m[1],
attributes: {},
children: []
}
// attributes
while (!(eos() || is('>') || is('?>') || is('/>'))) {
const attr = attribute()
if (!attr) return node
node.attributes[attr.name] = attr.value
}
// self closing tag
if (match(/^\s*\/>\s*/)) {
return node
}
match(/\??>\s*/)
// content
node.content = content()
// children
let child
while ((child = tag())) {
node.children!.push(child)
}
// closing
match(/^<\/[\w-:.]+>\s*/)
return node
}
function content () {
const m = match(reContent)
if (m) return m[1]
return ''
}
function attribute () {
const m = match(reAttr)
if (!m) return
return { name: m[1], value: strip(m[2]) }
}
function match (re: RegExp) {
const m = xml.match(re)
if (!m) return
xml = xml.slice(m[0].length)
return m
}
function eos () {
return xml.length === 0
}
function is (prefix: string) {
return xml.indexOf(prefix) === 0
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment