Skip to content

Instantly share code, notes, and snippets.

@thom4parisot
Last active August 29, 2015 13:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save thom4parisot/10409366 to your computer and use it in GitHub Desktop.
Save thom4parisot/10409366 to your computer and use it in GitHub Desktop.
XML Stream Update
'use strict';
var STYLE_ATTRIBUTE = 'text-style-name';
var styleMatches = function (item, styleName) {
if (!item || item.attributes === undefined || item.attributes[STYLE_ATTRIBUTE] === undefined) {
return false;
}
return item.attributes[STYLE_ATTRIBUTE].match(styleName);
};
var returnValue = function returnValue(){
return function (text){
return text;
};
};
var entity = function encodeEntity(str) {
return str.replace('"', '"');
};
module.exports = {
XMLInstruction:function instruction(tag) {
return tag.name + ' ' + tag.body;
},
applyTagFilters: function applyFilters(filters){
return function(tag){
filters
.filter(function(filter){
return filter.condition(tag)
})
.forEach(function(filter){
tag = filter.callback(tag);
});
return tag.name + Object.keys(tag.attributes || []).reduce(function(prev, key){
return prev + ' ' + key + '="'+ entity(tag.attributes[key]) +'"';
}, '');
}
},
replaceStyle: function (oldStyleName, newStyleName){
return function(item){
if (styleMatches(item, oldStyleName)) {
item.attributes[STYLE_ATTRIBUTE] = newStyleName;
}
return item;
}
},
returnValue: returnValue,
wrapValue: function(fragmentStart, fragmentEnd, transform){
transform = transform || returnValue();
return function (text){
return fragmentStart + transform(text) + fragmentEnd;
}
},
writeToStream: function writeToStream(stream, fn, text){
stream.write(fn(text));
}
};
#!/usr/bin/env node
var fileStream = require('fs').createReadStream('data.xml');
var xml = require('./stream-writer.js').rewrite(fileStream);
var replaceStyle = require('./convert-helpers.js').replaceStyle;
xml.node(replaceStyle('Text_20_body', 'BodyText'));
xml.node(replaceStyle(/Heading_\d+_1/, 'HeadingLevel1'));
xml.childOf('text:list-item', replaceStyle(/P\d+/, 'ListItem'));
xml.pipe(process.stdout);
<?xml version="1.0" encoding="UTF-8"?>
<root>
<section>
<text:h text-style-name="HeadingLevel1">Title 1</text:h>
<!-- some text comment -->
<text:p text-style-name="BodyText">Some text</text:p>
<text:list text-style-name="L20">
<text:list-item>
<text:p text-style-name="ListItem"><![CDATA[Bullet point 1]]></text:p>
</text:list-item>
<text:list-item>
<text:p text-style-name="ListItem">Bullet point 2</text:p>
</text:list-item>
</text:list>
</section>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<section>
<text:h text-style-name="Heading_20_1">Title 1</text:h>
<!-- some text comment -->
<text:p text-style-name="Text_20_body">Some text</text:p>
<text:list text-style-name="L20">
<text:list-item>
<text:p text-style-name="P12"><![CDATA[Bullet point 1]]></text:p>
</text:list-item>
<text:list-item>
<text:p text-style-name="P12">Bullet point 2</text:p>
</text:list-item>
</text:list>
</section>
</root>
{
"name": "node-streams",
"version": "0.0.0",
"description": "",
"main": "convert.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://gist.github.com/10409366.git"
},
"author": "",
"license": "MIT",
"bugs": {
"url": "https://gist.github.com/10409366"
},
"homepage": "https://gist.github.com/10409366",
"dependencies": {
"through": "^2.3.4",
"sax": "^0.6.0"
}
}
'use strict';
var through = require('through');
var sax = require('sax');
var helpers = require('./convert-helpers.js');
var returnValue = helpers.returnValue;
var wrapValue = helpers.wrapValue;
var writeToStream = helpers.writeToStream;
var instruction = helpers.XMLInstruction;
var applyFilters = helpers.applyTagFilters;
function withNode(filters, parser, fn){
filters.push({
condition: function(){ return true; },
callback: fn
});
}
function withChildNode(filters, parser, condition, fn){
filters.push({
active: false,
condition: function(tag){
var self = this;
// Activate the filter if the tag name condition is met
if (tag.name.match(condition) && !self.active){
self.active = true;
var closeTagFn = function(closeTag){
if (closeTag === tag.name && self.active){
self.active = false;
parser.removeListener('closetag', closeTagFn);
}
};
// Registering the auto-cleanup as we exit the tag
parser.on('closetag', closeTagFn);
}
return self.active;
},
callback: fn
});
}
module.exports = {
rewrite: function (readStream){
var filters = {
opentag: []
};
var parser = sax.createStream(false, { lowercase: true });
var outStream = through();
var write = writeToStream.bind(null, outStream);
var print = write.bind(null, returnValue());
var printComment = write.bind(null, wrapValue('<!--', '-->'));
var printCDATA = write.bind(null, wrapValue('<![CDATA[', ']]>'));
var printCloseTag = write.bind(null, wrapValue('</', '>'));
var printOpenTag = write.bind(null, wrapValue('<', '>', applyFilters(filters.opentag)));
var printInstruction = write.bind(null, wrapValue('<?', '?>', instruction));
outStream.node = withNode.bind(null, filters.opentag, parser);
outStream.childOf = withChildNode.bind(null, filters.opentag, parser);
parser.on('sgmldeclaration', print);
parser.on('doctype', print);
parser.on('text', print);
parser.on('comment', printComment);
parser.on('cdata', printCDATA);
parser.on('closetag', printCloseTag);
parser.on('opentag', printOpenTag);
parser.on('processinginstruction', printInstruction);
readStream.pipe(parser);
return outStream;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment