Skip to content

Commit

Permalink
Merge pull request #20 from GordonSmith/EXPAT_WASM
Browse files Browse the repository at this point in the history
feat(xml): Add simple XML parser based on expat
  • Loading branch information
GordonSmith authored Mar 22, 2020
2 parents dc893c6 + cafb0f6 commit 41fbcc1
Show file tree
Hide file tree
Showing 13 changed files with 1,260 additions and 4 deletions.
46 changes: 46 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"label": "Compile Watch",
"script": "compile-es6-watch",
"problemMatcher": [
"$tsc-watch"
],
"presentation": {
"group": "group-build"
}
},
{
"type": "npm",
"label": "Bundle Watch",
"script": "bundle-watch",
"problemMatcher": [],
"presentation": {
"group": "group-build"
}
},
{
"type": "npm",
"label": "Web Server",
"script": "dev-start",
"problemMatcher": [],
"presentation": {
"group": "group-build"
}
},
{
"label": "build",
"dependsOn": [
"Compile Watch",
"Bundle Watch",
"Web Server"
],
"group": "build",
"problemMatcher": []
}
]
}
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ npm install --save @hpcc-js/wasm
* `index.js` / `index.min.js` files: Exposes _all_ the available APIs for all WASM files.
* WASM Files:
* `graphvizlib.wasm`
* `expatlib.wasm`
* ...more to follow...

**Important**: WASM files are dynamically loaded at runtime (this is a browser / emscripten requirement), which has a few implications for the consumer:
Expand All @@ -29,6 +30,7 @@ npm install --save @hpcc-js/wasm
## API Reference
* [Common](#common)
* [GraphViz](#graphviz)
* [Expat](#expat)

### Common
Utility functions relating to @hpcc-js/wasm as a package
Expand Down Expand Up @@ -201,6 +203,58 @@ Convenience function that performs **patchwork** layout, is equivalent to `layou

Convenience function that performs **twopi** layout, is equivalent to `layout(dotSource, outputFormat, "twopi");`.

### Expat (`expatlib.wasm`)
Expat WASM library, provides a simplified wrapper around the Expat XML Parser library, see [libexpat.github.io](https://libexpat.github.io/) for c++ details.

#### Hello World
```html
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>GraphViz WASM</title>
<script src="https://unpkg.com/@hpcc-js/wasm/dist/index.min.js"></script>
<script>
var hpccWasm = window["@hpcc-js/wasm"];
</script>
</head>

<body>
<script>
const xml = `
<root>
<child xxx="yyy">content</child>
</root>
`;
var callback = {
startElement(tag, attrs) { console.log("start", tag, attrs); },
endElement(tag) { console.log("end", tag); },
characterData(content) { console.log("characterData", content); }
};
hpccWasm.parse(xml, callback);
</script>

</body>

</html>
```

#### Expat API

<a name="parse" href="#parse">#</a> **parse**(_xml_, _callback_) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/expat.ts "Source")

* **_xml_**: XML String.
* **_callback_**: Callback Object with the following methods:
* **startElement**(_tag_: string, _attrs_: {[key: string]: string]): void;
* **endElement**(_tag_: string): void;
* **characterData**(_content_: string): void;

Parses the XML with suitable callbacks.

**Note:** _characterData_ may get called several times for a single tag element.

## Building @hpcc-js/wasm
_Building is supported on both Linux (tested with Ubuntu 18.04) and Windows with WSL enabled (Ubuntu-18.04). Building in other environments should work, but may be missing certain prerequisites._

Expand Down
2 changes: 2 additions & 0 deletions cpp/expat/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ ADD_LIBRARY(expat STATIC
${EXPAT_LIB_DIR}/xmltok_ns.c
${EXPAT_LIB_DIR}/xmltok.c
)

ADD_SUBDIRECTORY(expatlib)
33 changes: 33 additions & 0 deletions cpp/expat/expatlib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
PROJECT(expatlib)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WASM=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web -s ALLOW_MEMORY_GROWTH=1")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s MODULARIZE=1 -s EXPORT_NAME='${CMAKE_PROJECT_NAME}'")

# Generate Glue from IDL file ---
ADD_CUSTOM_COMMAND(
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/main.idl
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/main_glue.js ${CMAKE_CURRENT_BINARY_DIR}/main_glue.cpp
COMMAND python ${CMAKE_BINARY_DIR}/../emsdk/upstream/emscripten/tools/webidl_binder.py ${CMAKE_CURRENT_SOURCE_DIR}/main.idl ${CMAKE_CURRENT_BINARY_DIR}/main_glue
)
SET_PROPERTY(SOURCE main.cpp APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/main_glue.cpp)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --post-js ${CMAKE_CURRENT_BINARY_DIR}/main_glue.js")
# --- --- ---

INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_BINARY_DIR}
${EXPAT_LIB_DIR}
)

ADD_EXECUTABLE(expatlib
main.cpp
)

TARGET_LINK_LIBRARIES(expatlib
expat
)

INSTALL(FILES
${CMAKE_CURRENT_BINARY_DIR}/expatlib.wasm
DESTINATION dist
COMPONENT runtime
)
100 changes: 100 additions & 0 deletions cpp/expat/expatlib/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "stack_parser.h"

#include <string>

class CExpat : public CExpatImpl<CExpat>
{
private:
typedef CExpatImpl<CExpat> BaseClass;

protected:
std::string m_tag;
std::string m_attrs;
std::string m_content;

public:
CExpat()
{
}

void OnPostCreate()
{
EnableStartElementHandler();
EnableEndElementHandler();
EnableCharacterDataHandler();
}

bool create()
{
return BaseClass::Create();
}

void destroy()
{
BaseClass::Destroy();
}

bool parse(const char *xml)
{
return BaseClass::Parse(xml, (int)strlen(xml), XML_TRUE);
}

const char *tag() const
{
return m_tag.c_str();
}

const char *attrs() const
{
return m_attrs.c_str();
}

const char *content() const
{
return m_content.c_str();
}

virtual void startElement()
{
}

virtual void endElement()
{
}

virtual void characterData()
{
}

virtual void OnStartElement(const XML_Char *pszName, const XML_Char **papszAttrs)
{
m_tag = pszName;
m_attrs = "";
for (XML_Char **itr = (XML_Char **)papszAttrs; *itr != NULL; itr += 2)
{
if (!m_attrs.empty())
{
m_attrs += "\1\1";
}
m_attrs += *itr;
m_attrs += "\1";
m_attrs += *(itr + 1);
}
startElement();
}

virtual void OnEndElement(const XML_Char *pszName)
{
m_tag = pszName;
endElement();
}

virtual void OnCharacterData(const XML_Char *pszData, int nLength)
{
m_content.assign(pszData, nLength);
characterData();
}
};

// Include JS Glue ---
#include "main_glue.cpp"
21 changes: 21 additions & 0 deletions cpp/expat/expatlib/main.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface CExpat
{
void CExpat();
boolean create();
void destroy();
boolean parse([Const] DOMString xml);
[Const] DOMString tag();
[Const] DOMString attrs();
[Const] DOMString content();
void startElement();
void endElement();
void characterData();
};

[JSImplementation = "CExpat"]
interface CExpatJS {
void CExpatJS();
void startElement();
void endElement();
void characterData();
};
Loading

0 comments on commit 41fbcc1

Please sign in to comment.