Skip to content

Commit

Permalink
Added option to parse XML from a string
Browse files Browse the repository at this point in the history
  • Loading branch information
rmraya committed Nov 24, 2023
1 parent f495c58 commit 1192b9f
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 23 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Open source XML library written in TypeScript

Implements a SAX parser that exposes the these methods from the `ContentHandler` interface:

* initialize(): void;
* setCatalog(catalog: Catalog): void;
* startDocument(): void;
* endDocument(): void;
Expand Down Expand Up @@ -53,10 +54,16 @@ export class Test {
let contentHandler: ContentHandler = new DOMBuilder();
let xmlParser = new SAXParser();
xmlParser.setContentHandler(contentHandler);
xmlParser.parse("test.xml");
xmlParser.parseFile("test.xml");
let doc: XMLDocument = (contentHandler as DOMBuilder).getDocument();
let root: XMLElement = doc.getRoot();
console.log(root.toString());

// build the document again, this time from a string
xmlParser.parseString(doc.toString());
let newDoc = (contentHandler as DOMBuilder).getDocument();
console.log(newDoc.getRoot().toString());

} catch (error: any) {
if (error instanceof Error) {
console.log(error.message);
Expand Down
5 changes: 5 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rm -rf dist/
rm -rf node_modules/
rm package-lock.json
npm install
npm run build
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "typesxml",
"productName": "TypesXML",
"version": "1.1.0",
"version": "1.2.0",
"description": "Open source XML library written in TypeScript",
"scripts": {
"build": "tsc"
Expand All @@ -22,7 +22,7 @@
"url": "https://github.com/rmraya/TypesXML.git"
},
"devDependencies": {
"@types/node": "^20.9.4",
"@types/node": "^20.10.0",
"typescript": "^5.3.2"
}
}
2 changes: 1 addition & 1 deletion sonar-project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
sonar.projectKey=TypesXML
# this is the name displayed in the SonarQube UI
sonar.projectName=TypesXML
sonar.projectVersion=1.1.0
sonar.projectVersion=1.2.0

# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# Since SonarQube 4.2, this property is optional if sonar.modules is set.
Expand Down
5 changes: 2 additions & 3 deletions ts/Catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class Catalog {
let contentHandler: ContentHandler = new DOMBuilder();
let parser: SAXParser = new SAXParser();
parser.setContentHandler(contentHandler);
parser.parse(catalogFile);
parser.parseFile(catalogFile);
let catalogDocument: XMLDocument = (contentHandler as DOMBuilder).getDocument();
let catalogRoot: XMLElement = catalogDocument.getRoot();
if (catalogRoot.getName() !== 'catalog') {
Expand Down Expand Up @@ -245,8 +245,7 @@ export class Catalog {

matchSystem(systemId: string): string {
if (systemId) {
for (let i: number = 0; i < this.systemRewrites.length; i++) {
let pair: string[] = this.systemRewrites[i];
for (let pair of this.systemRewrites) {
if (systemId.startsWith(pair[0])) {
systemId = pair[1] + systemId.substring(pair[0].length);
}
Expand Down
1 change: 1 addition & 0 deletions ts/ContentHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { XMLAttribute } from "./XMLAttribute";

export interface ContentHandler {

initialize(): void;
setCatalog(catalog: Catalog): void;

startDocument(): void;
Expand Down
2 changes: 1 addition & 1 deletion ts/DOMBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class DOMBuilder implements ContentHandler {
catalog: Catalog;
grammarUrl: string;

constructor() {
initialize(): void {
this.document = new XMLDocument();
this.stack = new Array();
this.inCdData = false;
Expand Down
5 changes: 3 additions & 2 deletions ts/FileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
* Maxprograms - initial API and implementation
*******************************************************************************/

import { openSync, readSync, closeSync, statSync, Stats } from "fs";
import { Stats, closeSync, openSync, readSync, statSync } from "fs";
import { XMLReader } from "./XMLReader";

export class FileReader {
export class FileReader implements XMLReader {

fileHandle: number;
encoding: BufferEncoding;
Expand Down
27 changes: 21 additions & 6 deletions ts/SAXParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@

import { ContentHandler } from "./ContentHandler";
import { FileReader } from "./FileReader";
import { StringReader } from "./StringReader";
import { XMLAttribute } from "./XMLAttribute";
import { XMLReader } from "./XMLReader";
import { XMLUtils } from "./XMLUtils";

export class SAXParser {

contentHandler: ContentHandler;
reader: FileReader;
reader: XMLReader;
pointer: number;
buffer: string;
fileSize: number;
encoding: BufferEncoding;
elementStack: number;
characterRun: string;
rootParsed: boolean;
Expand All @@ -38,11 +38,26 @@ export class SAXParser {
this.contentHandler = contentHandler;
}

parse(path: string, encoding?: BufferEncoding): void {
this.encoding = encoding ? encoding : FileReader.detectEncoding(path);
parseFile(path: string, encoding?: BufferEncoding): void {
if (!this.contentHandler) {
throw new Error('ContentHandler not set');
}
if (!encoding) {
encoding = FileReader.detectEncoding(path);
}
this.reader = new FileReader(path, encoding);
this.fileSize = this.reader.getFileSize();
this.buffer = this.reader.read();
this.contentHandler.initialize();
this.readDocument();
}

parseString(string: string): void {
if (!this.contentHandler) {
throw new Error('ContentHandler not set');
}
this.reader = new StringReader(string);
this.buffer = this.reader.read();
this.contentHandler.initialize();
this.readDocument();
}

Expand Down
40 changes: 40 additions & 0 deletions ts/StringReader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2023 Maxprograms.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse License 1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-v10.html
*
* Contributors:
* Maxprograms - initial API and implementation
*******************************************************************************/
import { XMLReader } from "./XMLReader";

export class StringReader implements XMLReader {

CHUNK_SIZE: number = 4096;

data: string;
position: number;

constructor(data: string) {
this.data = data;
this.position = 0;
}

dataAvailable(): boolean {
return this.position < this.data.length;
}

read(): string {
let amount: number = this.CHUNK_SIZE;
if (this.position + this.CHUNK_SIZE > this.data.length) {
amount = this.data.length - this.position;
}
let result: string = this.data.substring(this.position, amount);
this.position += amount;
return result;
}

}
14 changes: 7 additions & 7 deletions ts/XMLDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ export class XMLDocument implements XMLNode {
}

getRoot(): XMLElement | undefined {
for (let i = 0; i < this.content.length; i++) {
if (this.content[i] instanceof XMLElement) {
return this.content[i] as XMLElement;
for (let node of this.content) {
if (node instanceof XMLElement) {
return node;
}
}
return undefined;
Expand All @@ -50,9 +50,9 @@ export class XMLDocument implements XMLNode {
}

getDocumentType(): XMLDocumentType | undefined {
for (let i = 0; i < this.content.length; i++) {
if (this.content[i] instanceof XMLDocumentType) {
return this.content[i] as XMLDocumentType;
for (let node of this.content) {
if (node instanceof XMLDocumentType) {
return node;
}
}
return undefined;
Expand All @@ -64,7 +64,7 @@ export class XMLDocument implements XMLNode {

getXmlDeclaration(): XMLDeclaration | undefined {
if (this.content[0] instanceof XMLDeclaration) {
return this.content[0] as XMLDeclaration;
return this.content[0];
}
return undefined;
}
Expand Down
16 changes: 16 additions & 0 deletions ts/XMLReader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*******************************************************************************
* Copyright (c) 2023 Maxprograms.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse License 1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-v10.html
*
* Contributors:
* Maxprograms - initial API and implementation
*******************************************************************************/

export interface XMLReader {
dataAvailable(): boolean;
read(): string;
}

0 comments on commit 1192b9f

Please sign in to comment.