Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get list of tags used in document? #258

Closed
mnpenner opened this issue Nov 30, 2016 · 16 comments
Closed

Get list of tags used in document? #258

mnpenner opened this issue Nov 30, 2016 · 16 comments
Labels

Comments

@mnpenner
Copy link

Environment

  • Version of docxtemplater : 3.0.0
  • Used docxtemplater-modules : No
  • Runner : Browser/Node.JS/... Node v6.9.1

How to reproduce my problem :

Is it possible to get a list of tags used inside a document?

I want to extract all the tags so that I can ask the user some questions before I generate the doc.

@edi9999
Copy link
Member

edi9999 commented Nov 30, 2016

2022 Update

The easiest way is to follow this documentation example : https://docxtemplater.com/docs/faq/#get-list-of-placeholders

Old answer

This is something that can be done using a module. Here is an example :

const _ = require("lodash");

class InspectModule {
    constructor() {
        this.inspect = {};
    }
    set(obj) {
        if (obj.inspect) {
            this.inspect = _.merge({}, this.inspect, obj.inspect);
        }
    }
}

const getTags = function (postParsed) {
    return postParsed.filter(function (part) {
        return part.type === "placeholder";
    }).reduce(function (tags, part) {
        tags[part.value] = {};
        if (part.subparsed) {
            tags[part.value] = getTags(part.subparsed);
        }
        return tags;
    }, {});
}
const doc = new Docxtemplater();
doc.loadZip(...)
const inspectModule = new InspectModule();
doc.attachModule(inspectModule);
try {
    doc.compile()
}
catch (error) {
    var e = {
        message: error.message,
        name: error.name,
        stack: error.stack,
        properties: error.properties,
    }
    console.log(JSON.stringify({error: e}));
    // The error thrown here contains additional information when logged with JSON.stringify (it contains a property object).
    throw error;
}
const postParsed = inspectModule.inspect.postparsed;
console.log(JSON.stringify({p: postParsed}));
console.log(JSON.stringify({tag: getTags(postParsed)}));

However, this is quite experimental, and could potentially break in future releases.

@PaulMcGuinness
Copy link

PaulMcGuinness commented Dec 1, 2016

I went for a simpler approach as I was only interested in {#groups}

var a=String(doc.getFullText()).match(/{#[a-z]{1,10}}/g);

but this would return an array of all tags (up to 20 chars in length):-

var a=String(doc.getFullText()).match(/{[a-z]{1,20}}/g);

@bunnyvishal6
Copy link

bunnyvishal6 commented Nov 1, 2017

@edi9999 what is testUtils ? in your example code stated above?

const doc = testUtils.createDoc("tag-loop-example.docx");

@edi9999
Copy link
Member

edi9999 commented Nov 1, 2017

It is just a method that creates the doc instead of doing

const doc = new Docxtemplater();
doc.loadZip(...)

@bunnyvishal6
Copy link

@edi9999 can you please provide some working code to get tags.

@bunnyvishal6
Copy link

@edi9999 here is my code

const _ = require("lodash"),
    path = require('path'),
    JSZip = require('jszip'),
    Docxtemplater = require('docxtemplater'),
    fs = require('fs');

class InspectModule {
    constructor() {
        this.inspect = {};
    }
    set(obj) {
        if (obj.inspect) {
            this.inspect = _.merge({}, this.inspect, obj.inspect);
        }
    }
}

const getTags = function (postParsed) {
    return postParsed.filter(function (part) {
        return part.type === "placeholder";
    }).reduce(function (tags, part) {
        tags[part.value] = {};
        if (part.subparsed) {
            tags[part.value] = getTags(part.subparsed);
        }
        return tags;
    }, {});
}

//Load the docx file as a binary
let content = fs
.readFileSync(path.resolve(__dirname, 'docs/test.docx'), 'binary');
let zip = new JSZip(content);
let doc = new Docxtemplater();
doc.loadZip(zip);
let inspectModule = new InspectModule();
doc.attachModule(inspectModule);
doc.render();
let postParsed = inspectModule.inspect.postparsed;
console.log(JSON.stringify({p: postParsed}));
console.log(JSON.stringify({tag: getTags(postParsed)}));
[template.zip](https://github.com/open-xml-templating/docxtemplater/files/1435172/template.zip)

here is the error I get

G:\learn\test\node_modules\docxtemplater\js\errors.js:52
        throw err;
        ^
Error: Multi error
    at new XTTemplateError (G:\learn\test\node_modules\docxtemplater\js\errors.js:19:15)
    at throwMultiError (G:\learn\test\node_modules\docxtemplater\js\errors.js:46:12)
    at XmlTemplater.errorChecker (G:\learn\test\node_modules\docxtemplater\js\xml-templater.js:119:5)
    at XmlTemplater.parse (G:\learn\test\node_modules\docxtemplater\js\xml-templater.js:104:9)
    at Docxtemplater.compileFile (G:\learn\test\node_modules\docxtemplater\js\docxtemplater.js:88:16)
    at G:\learn\test\node_modules\docxtemplater\js\docxtemplater.js:119:13
    at Array.forEach (<anonymous>)
    at Docxtemplater.compile (G:\learn\test\node_modules\docxtemplater\js\docxtemplater.js:117:24)
    at Docxtemplater.render (G:\learn\test\node_modules\docxtemplater\js\docxtemplater.js:160:9)

@edi9999
Copy link
Member

edi9999 commented Nov 1, 2017

Ok, I see, this happens becaus of a rendering error probably.

Can you try to replace doc.render() by doc.compile() and see if that helps ?

@edi9999
Copy link
Member

edi9999 commented Nov 1, 2017

I have also updated the code above with a try / catch statement. Can you update your code and report the result ?

@bunnyvishal6
Copy link

bunnyvishal6 commented Nov 2, 2017

@edi9999 sorry for late reply. I got error even after changing doc.render() to doc.compile().
here is my code

const _ = require("lodash"),
    path = require('path'),
    JSZip = require('jszip'),
    Docxtemplater = require('docxtemplater'),
    fs = require('fs');

class InspectModule {
    constructor() {
        this.inspect = {};
    }
    set(obj) {
        if (obj.inspect) {
            this.inspect = _.merge({}, this.inspect, obj.inspect);
        }
    }
}

const getTags = function (postParsed) {
    return postParsed.filter(function (part) {
        return part.type === "placeholder";
    }).reduce(function (tags, part) {
        tags[part.value] = {};
        if (part.subparsed) {
            tags[part.value] = getTags(part.subparsed);
        }
        return tags;
    }, {});
}

//Load the docx file as a binary
let content = fs
.readFileSync(path.resolve(__dirname, 'docs/test.docx'), 'binary');
let zip = new JSZip(content);
let doc = new Docxtemplater();
doc.loadZip(zip);
let inspectModule = new InspectModule();
doc.attachModule(inspectModule);
try {
    doc.compile()
}
catch (error) {
    var e = {
        message: error.message,
        name: error.name,
        stack: error.stack,
        properties: error.properties,
    }
    console.log(JSON.stringify({error: e}));
    // The error thrown here contains additional information when logged with JSON.stringify (it contains a property object).
    throw error;
}
let postParsed = inspectModule.inspect.postparsed;
console.log(JSON.stringify({p: postParsed}));
console.log(JSON.stringify({tag: getTags(postParsed)}));

here is the error I get

PS G:\learn\test> node server.js
{}
G:\learn\test\server.js:19
    return postParsed.filter(function (part) {
                      ^

TypeError: Cannot read property 'filter' of undefined
    at getTags (G:\learn\test\server.js:19:23)
    at Object.<anonymous> (G:\learn\test\server.js:54:34)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
[test.zip](https://github.com/open-xml-templating/docxtemplater/files/1436789/test.zip)

@edi9999
Copy link
Member

edi9999 commented Nov 3, 2017

Can you do

console.log(JSON.stringify({"iModule": iModule}));

just after doc.compile()

Are you running version 3.1.11 of docxtemplater ?

@bunnyvishal6
Copy link

bunnyvishal6 commented Nov 3, 2017

@edi9999 yes I'm using docxtemplater version 3.1.11
here I added console.log(JSON.stringify({"iModule": inspectModule})); after doc.compile()

const _ = require("lodash"),
    path = require('path'),
    JSZip = require('jszip'),
    Docxtemplater = require('docxtemplater'),
    fs = require('fs');

class InspectModule {
    constructor() {
        this.inspect = {};
    }
    set(obj) {
        if (obj.inspect) {
            this.inspect = _.merge({}, this.inspect, obj.inspect);
        }
    }
}

const getTags = function (postParsed) {
    return postParsed.filter(function (part) {
        return part.type === "placeholder";
    }).reduce(function (tags, part) {
        tags[part.value] = {};
        if (part.subparsed) {
            tags[part.value] = getTags(part.subparsed);
        }
        return tags;
    }, {});
}

//Load the docx file as a binary
let content = fs
.readFileSync(path.resolve(__dirname, 'docs/test.docx'), 'binary');
let zip = new JSZip(content);
let doc = new Docxtemplater();
doc.loadZip(zip);
let inspectModule = new InspectModule();
doc.attachModule(inspectModule);
try {
    doc.compile();
    console.log(JSON.stringify({"iModule": inspectModule}));
}
catch (error) {
    var e = {
        message: error.message,
        name: error.name,
        stack: error.stack,
        properties: error.properties,
    }
    console.log(JSON.stringify({error: e}));
    // The error thrown here contains additional information when logged with JSON.stringify (it contains a property object).
    throw error;
}
let postParsed = inspectModule.inspect.postparsed;
console.log(JSON.stringify({p: postParsed}));
console.log(JSON.stringify({tag: getTags(postParsed)}));

here is the url to gist file containing the output
https://gist.github.com/bunnyvishal6/d3d0210de25d3a05bdcab01ec3adcf13

@edi9999
Copy link
Member

edi9999 commented Nov 3, 2017

Can you update to docxtemplater 3.1.12. It should work with that version

@edi9999
Copy link
Member

edi9999 commented Nov 3, 2017

(I just published it)

@edi9999 edi9999 reopened this Nov 3, 2017
@bunnyvishal6
Copy link

bunnyvishal6 commented Nov 4, 2017

@edi9999 Awesome! thank you very much. please consider including getTag method to docxtemplater.

@edi9999
Copy link
Member

edi9999 commented Feb 20, 2018

It is now possible to get the list of tags of the document by writing less code.

https://docxtemplater.readthedocs.io/en/latest/faq.html#get-list-of-placeholders

@bunnyvishal6
Copy link

@edi9999 awesome thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants