@file-type/xml
Advanced tools
Comparing version 0.1.1 to 0.2.0
104
lib/index.js
@@ -18,9 +18,13 @@ | ||
if (startsWith(array,[60, 63, 120, 109, 108, 32])) { | ||
return {xml: true, encoding: 'utf-8'} | ||
return {xml: true, encoding: 'utf-8', offset: 0} | ||
} else if (startsWith(array,[0xEF, 0xBB, 0xBF, 60, 63, 120, 109, 108, 32])) { // UTF-8 BOM | ||
return {xml: true, encoding: 'utf-8'} | ||
return {xml: true, encoding: 'utf-8', offset: 3} | ||
} else if (startsWith(array,[0xFE, 0xFF, 0, 60, 0, 63, 0, 120, 0, 109, 0, 108, 0, 32 ])) { | ||
return {xml: true, encoding: 'utf-16be'} | ||
return {xml: true, encoding: 'utf-16be', offset: 2} | ||
} else if (startsWith(array,[0xFF, 0xFE, 60, 0, 63, 0, 120, 0, 109, 0, 108, 0, 32, 0 ])) { | ||
return {xml: true, encoding: 'utf-16le'} | ||
return {xml: true, encoding: 'utf-16le', offset: 2} | ||
} else if (startsWith(array,[0, 60, 0, 63, 0, 120, 0, 109, 0, 108, 0, 32 ])) { | ||
return {xml: true, encoding: 'utf-16be', offset: 0} | ||
} else if (startsWith(array,[60, 0, 63, 0, 120, 0, 109, 0, 108, 0, 32, 0 ])) { | ||
return {xml: true, encoding: 'utf-16le', offset: 0} | ||
} | ||
@@ -62,3 +66,4 @@ return {xml: false, encoding: undefined} | ||
/** | ||
* Maps the root element name to corresponding file-type | ||
* Maps the root element name to corresponding file-type. | ||
* Used for Non-namespaced XML | ||
* @type {{rss: {ext: string, mime: string}}} | ||
@@ -74,47 +79,70 @@ */ | ||
mime: 'application/vnd.recordare.musicxml+xml', | ||
} | ||
}, | ||
svg: { | ||
ext: 'svg', | ||
mime: 'image/svg+xml', | ||
}, | ||
} | ||
export const detectXml = async tokenizer => { | ||
export class XmlTextDetector { | ||
const buffer = new Uint8Array(512); | ||
constructor() { | ||
this.firstTag = true; | ||
this.onEnd = false; | ||
this.parser = sax.parser(true); | ||
this.depth = 0; | ||
this.validClose = false; | ||
// Increase sample size from 12 to 256. | ||
await tokenizer.peekBuffer(buffer, {length: 128, mayBeLess: true}); | ||
const {xml, encoding} = isXml(buffer); | ||
if (xml) { | ||
let fileType; | ||
const parser = sax.parser(true); | ||
let firstTag = true; | ||
let onEnd = false; | ||
parser.onerror = e => { | ||
onEnd = true; | ||
this.parser.onerror = e => { | ||
this.onEnd = true; | ||
}; | ||
parser.onopentag = node => { | ||
if (!firstTag) { | ||
this.parser.onopentag = node => { | ||
++this.depth; | ||
if (!this.firstTag || this.onEnd) { | ||
return; | ||
} | ||
firstTag = false; | ||
this.firstTag = false; | ||
const nsNode = extractNsElement(node); | ||
if (nsNode.ns) { | ||
// Resolve file-type boot root element namespace | ||
fileType = namespaceMapping[nsNode.ns]; | ||
this.fileType = namespaceMapping[nsNode.ns.toLowerCase()]; | ||
} else { | ||
// Fall back on element name if there is no namespace | ||
fileType = rootNameMapping[nsNode.name]; | ||
this.fileType = rootNameMapping[nsNode.name?.toLowerCase()]; | ||
} | ||
if (fileType) { | ||
onEnd = true; | ||
if (this.fileType) { | ||
this.onEnd = true; | ||
} | ||
}; | ||
parser.onend = () => { | ||
onEnd = true; | ||
this.parser.onend = () => { | ||
this.onEnd = true; | ||
}; | ||
} | ||
write(text) { | ||
this.parser.write(text); | ||
} | ||
close() { | ||
this.parser.close(); | ||
this.onEnd = true; | ||
} | ||
} | ||
export const detectXml = async tokenizer => { | ||
const buffer = new Uint8Array(512); | ||
// Increase sample size from 12 to 256. | ||
await tokenizer.peekBuffer(buffer, {length: 128, mayBeLess: true}); | ||
const {xml, encoding, offset} = isXml(buffer); | ||
if (xml) { | ||
await tokenizer.ignore(offset); | ||
let fileType; | ||
const xmlTextDetector = new XmlTextDetector(); | ||
const textDecoder = new TextDecoder(encoding); | ||
@@ -126,10 +154,9 @@ | ||
const text = textDecoder.decode(portion); | ||
parser.write(text); | ||
xmlTextDetector.write(text); | ||
if (len < buffer.length) { | ||
parser.close(); | ||
onEnd = true; | ||
xmlTextDetector.close(); | ||
} | ||
} while(!onEnd) | ||
} while(!xmlTextDetector.onEnd) | ||
return fileType ?? { | ||
return xmlTextDetector.fileType ?? { | ||
ext: 'xml', | ||
@@ -140,2 +167,3 @@ mime: 'application/xml', | ||
}; | ||
}; | ||
{ | ||
"name": "@file-type/xml", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"description": "XML detection plugin", | ||
@@ -12,9 +12,14 @@ "type": "module", | ||
"file-type", | ||
"detect", | ||
"detection", | ||
"detector", | ||
"XML", | ||
"signature", | ||
"namespace", | ||
"SVG", | ||
"XHTML", | ||
"RSS", | ||
"KML" | ||
"KML", | ||
"GML", | ||
"MusicXML" | ||
], | ||
@@ -21,0 +26,0 @@ "dependencies": { |
@@ -13,3 +13,3 @@ [![NPM version](https://img.shields.io/npm/v/@file-type/xml.svg)](https://npmjs.org/package/@file-type/xml) | ||
### Usage | ||
## Usage | ||
@@ -26,2 +26,19 @@ The following example shows how add the XML detector to [file-type](https://github.com/sindresorhus/file-type). | ||
You can also use the XML detector outside file-type: | ||
```js | ||
import {XmlTextDetector} from 'index.js'; | ||
xmlTextDetector.write('<svg xmlns="http://www.w3.org/2000/svg"><path fill="#00CD9F"/></svg>'); | ||
const fileType = xmlTextDetector.fileType; | ||
console.log(JSON.stringify(fileType)); // Outputs: {"ext":"svg","mime":"image/svg+xml"} | ||
``` | ||
## Support file formats | ||
- [XML](https://en.wikipedia.org/wiki/XML) (default for XML, unless more specific format was detected) | ||
- [GML (Geography Markup Language)](https://en.wikipedia.org/wiki/Geography_Markup_Language) | ||
- [KML (Keyhole Markup Language)](https://en.wikipedia.org/wiki/XHTML) | ||
- [MusicXML, Uncompressed](https://en.wikipedia.org/wiki/MusicXML) | ||
- [RSS (RDF Site Summary or Really Simple Syndication)](https://en.wikipedia.org/wiki/RSS) | ||
- [SVG: (Scalable Vector Graphics)](https://en.wikipedia.org/wiki/SVG) | ||
- [XHTML](https://en.wikipedia.org/wiki/XHTML) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6714
141
43