UNPKG

yhbatis

Version:

Like Mybatis for nodejs By YYH.

64 lines (63 loc) 11 kB
{ "name": "xml-digester", "version": "0.0.5", "description": "convert XML to JSON", "tags": [ "xml", "json", "xml-digester" ], "author": { "name": "Victor Volle" }, "dependencies": { "sax": ">= 0.5.1" }, "devDependencies": { "nodeunit": ">=0.8.1", "jshint": "2.0.1" }, "main": "lib/xml-digester.js", "scripts": { "test": "jshint lib && node_modules/.bin/jshint test && nodeunit test/*" }, "repository": { "type": "git", "url": "http://github.com/vrvolle/xml-digester" }, "license": { "type": "MIT" }, "readmeFilename": "README.md", "contributors": [ { "name": "Victor Volle", "email": "v.volle@computer.org" } ], "readme": "# XML Digester\n\nMaps Xml to JavaScript objects while allowing you to influence the conversion. Thereby some unusual Xml documents can be mapped with ease.\n\n## Disclaimer\nThis is my first node module and I have never _really_ programmed in JavaScript before. So be warned. If you do not need the features of this converter, you should probably use one of the [alternatives](#alternatives)\n\n## Why yet another Xml-to-JavaScript mapper? \n\nI had an Xml I needed to convert with an unusual charcteristic:\n\n <nodes>\n <crossing/>\n <street/>\n <cross-walk/>\n <street/>\n <end-of-town/>\n </nodes>\n\nI needed to preserve the order of the 'nodes' (\"crossing\", \"street\", etc.):\n\n { nodes: [ {name:\"crossing\"}, {name:\"street\"}, ... ] }\n\n\nBut none of the converters I tried (see below [alternatives](#alternatives)), allowed me to do that. If the nodes were of the same name they would automatically be collected into an array:\n\n <nodes>\n <node kind=\"crossing\"/>\n <node kind=\"street\"/>\n <node kind=\"cross-walk\"/>\n <node kind=\"street\"/>\n <node kind=\"end-of-town\"/>\n </nodes>\n\nwhich would result in\n\n { nodes: { node: [ { kind: 'crossing' }, { kind: 'street' }, ... ] } }\n\nbut I didn't want to create a stylesheet that first transformed these documents. \n\nThere are other mappers like [xmldom][xmldom] that create a whole Dom tree, but I wanted something simpler and something that could easily be extended by someone else.\n\n## Basic usage\n\n```javascript\nvar xml_digester = require(\"xml-digester\");\nvar digester = xml_digester.XmlDigester({});\n\nvar xml = \"<root>\"\n + \"<foo>foo1</foo>\"\n + \"<bar>bar1></bar>\"\n + \"<foo>foo2</foo>\"\n + \"</root>\"\n\ndigester.digest(xml, function(err, result) {\n if (err) { \n console.log(err);\n } else {\n console.log(result);\n // result will be { root: { foo: [ 'foo1', 'foo2' ], bar: 'bar1>' } }\n }\n})\n```\n\nThis is the normal mapping behaviour, which all other converters offer. So it should be possible to simply replace your existing mapper with xml-digester.\n\n## Advanced usage\n\nIf you need to influence the mapping you can declare that certain Xml elements should be converted by a special handler. The declaration supports a very minimal subset of XPath:\n\n- **`foo`** matches all 'foo' elements\n- **`bar/foo`** matches all 'foo' elements which have a 'bar' element as parent\n- **`bar//foo`** matches all 'foo' elements which have a 'bar' element as ancestor\n- **`/bar//foo`** matches all 'foo' elements which have a 'bar' element as root element\n- **`bar/*`** matches all elements which have a 'bar' element as parent\n- **`bar/*/foo`** matches all 'foo' elements which have a 'bar' element as grand parent\n\nThere are three predefined handlers. \n\n1. The SkipElementsHandler (`xml_digester.SkipElementsHandler`) that just removes elements (and their child elements)\n2. The OrderElementsHandler (`xml_digester.OrderedElementsHandler`) that is used to preserve the order of elements (see [Why ...](#whyyetanotherxml-to-javascriptmapper)) \n3. And the DefaultHandler (`xml_digester.DefaultHandler`), which is used normally but which can be used by another handler as well\n\nTo use the handler you have to set it as an option to the digester:\n\n```javascript\nvar xml_digester = require(\"../lib/xml-digester\");\n\nvar handler = new xml_digester.OrderedElementsHandler(\"kind\");\nvar options = {\n \"handler\": [\n { \"path\": \"nodes/*\", \"handler\": handler}\n ]};\nvar digester = xml_digester.XmlDigester(options);\nvar xml = \"<nodes>\"\n + \"<crossing/><street/><cross-walk/><street/><end-of-town/>\"\n + \"</nodes>\"\n\ndigester.digest(xml, function(err, result) {\n if (err) { \n } else {\n console.log(result);\n // result will be { nodes: [ { kind: 'crossing' }, { kind: 'street' }, ... ] }\n }\n})\n```\n\nSince the name of the nodes should preserved, you can define a property-name (in the above example it is 'kind'). The Xml Element name will then be stored in the JavaScript object in that property.\n\nIf you do not give a property-name, the '_name' property will be used. But this property is not 'enumerable', i.e. Object.keys(node) will not list the '_name' property.\n\nIf there are multiple paths that match a given Xml element, the handler of the first matching path in the 'handler' array will be used.\n\n## Create your own handler\n\nYou can create your own handler, if you understand some of the inner workings of the XmlDigester. For now I would advise you not to do that, because the API might change. \n\n### The handler API\n\nEach handler must (currently) implement the following functions:\n\n#### `onopentag(node, digester)`\n\nThe DefaultHandler \n\n1. pushes the current object on the object stack (`digester.object_stack`)\n2. creates a new object based on the attributes of the element and ...\n3. ... makes that object the current object (`digester.current_object`)\n\n#### `onclosetag(node_name, digester)`\n\nThe DefaultHandler\n\n1. gets the parent object from the object stack (`digester.object_stack`)\n1. If the current node has no children and no attributes but some text content, then the text will be used as current object\n1. assigns the current object to a property (using the \"node_name\" as property name)\n \n - if there already is a property with that name, an array will be created that contains the previous and the new object (every following object with the same name will simply be added to the array)\n\n1. reinstates the parent object as the current object\n\nThe easiest way to write a new handler is to reuse the DefaultHandler and to use it as delegate: \n\n```javascript\nfunction MyHandler() {\n this.defaultHandler = new xml_digester.DefaultHandler();\n}\n\nMyHandler.prototype.onopentag = function(node, digester) {\n this.defaultHandler.onopentag(node, digester);\n}\n\nMyHandler.prototype.onclosetag = function(node_name, digester) {\n var parent_object = digester.object_stack.pop();\n\n // uses the text content as a the current object\n // if the current object has no properties\n this.defaultHandler.textifyCurrentObject(digester);\n\n parent_object[digester.current_object.name] = digester.current_object.content;\n\n digester.current_object = parent_object;\n}\n```\n\nIn the above example only the `onclosetag` function is adapted. The XML may look \nlike:\n\n <root>\n <bar name=\"bar1\"><content>some_text</content></bar>\n <bar name=\"bar2\"><content>some_other_text</content></bar>\n </root>\n\nNormally the object would be: \n\n { root: \n { bar: \n [ { name: 'bar1', content: 'some_text' },\n { name: 'bar2', content: 'some_other_text' } ] } }\n\nThe above handler gets rid of the \"bar\" property and directly assign the 'bar' _elements_ to the root object using their \"name\" as property-name in the root object and the \"content\" as value.\n\n { root: { bar1: 'some_text', bar2: 'some_other_text' } }\n\n### Logging/Debugging\n\nThis module contains a very simple debugging mechanism that allows you to inspect the inner workings.\n\n var _logger = xml_digester._logger;\n _logger.level(_logger.TRACE_LEVEL);\n\nThe following logging level are supported \n\n> **\\_logger.ERROR\\_LEVEL** \n> **\\_logger.WARN\\_LEVEL** \n> **\\_logger.INFO\\_LEVEL** \n> **\\_logger.DEBUG\\_LEVEL** \n> **\\_logger.TRACE\\_LEVEL**\n\nIf you look at logging in `examples/basic-example.js` you should see something like\n\n![][trace]\n\n[trace]: https://raw.github.com/vrvolle/xml-digester/master/doc/trace.png \n\nYou can see\n\n - all the opening tags (with their parent tags), e.g `<root><foo>`\n - each current element as returned by sax-js: `{ name: 'root', attributes: {}, isSelfClosing: false }`\n - all the closing tags (with their parent tags), e.g `<root><`**/**`foo>`\n - and the current object stack:\n\n DEBUG: -> document\n DEBUG: -> root\n\n the object stack always contains a top level element 'document' and will normally directly correspond to the Xml element hierarchy, but if you manipulate the object stack (as the OrderedElementsHandler does) the stack might look completely different.\n\nThis logging should really help you, when you try to develop your own handler.\n\n\n## TODOs\n\n1. Handling of CDATA\n2. Some handling of Namespaces\n3. Forwarding of any sax-js options\n4. Using Buffers as well as Strings\n5. Using Streams\n\n## Alternatives\n\n[xml2json](https://github.com/buglabs/node-xml2json) \n[xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) \n[libxml-to-js](https://github.com/SaltwaterC/libxml-to-js) \n[xml-object-stream](https://github.com/idottv/xml-object-stream) \n[xmldom][xmldom] \n[xml-stream][xmlstream] \n[xml-mapping](https://github.com/lindory-project/node-xml-mapping) \n[node-xml](https://github.com/robrighter/node-xml) \n\nThe above are the ones I tried. See \n\n[https://github.com/joyent/node/wiki/modules#wiki-parsers-xml](https://github.com/joyent/node/wiki/modules#wiki-parsers-xml)\n\nfor the full list.\n\n## Dependencies\n\nThe Xml Digester is based on [Issac Schlueter's sax-js](https://github.com/isaacs/sax-js).\n\nThat library also works in the browser! It would be great if anyone\nwere willing to test Xml Digester in the browser and send me a pull request ...\n\n[xmldom]: https://github.com/jindw/xmldom\n[xmlstream]: https://github.com/assistunion/xml-stream", "bugs": { "url": "https://github.com/vrvolle/xml-digester/issues" }, "_id": "xml-digester@0.0.5", "dist": { "shasum": "5be0572351cbe307b3dedc59ab844a669a8c434f", "tarball": "http://registry.npmjs.org/xml-digester/-/xml-digester-0.0.5.tgz" }, "_from": "xml-digester@", "_npmVersion": "1.2.25", "_npmUser": { "name": "vivo", "email": "v.volle@computer.org" }, "maintainers": [ { "name": "vivo", "email": "v.volle@computer.org" } ], "directories": {}, "_shasum": "5be0572351cbe307b3dedc59ab844a669a8c434f", "_resolved": "https://registry.npmjs.org/xml-digester/-/xml-digester-0.0.5.tgz", "homepage": "https://github.com/vrvolle/xml-digester" }