简体   繁体   中英

Passing a variable or property value to a method in a JavaScript object returns “undefined”

I'm trying to build an xml file from 2 JSON objects through 2 cascading loops. In the second loop, I can't find how to pass a value from the previous loop:

In the example below, I would like to pass the "docnumber" value to my second loop (through GroupsACLJSON) in order to build the "acl" node from the second JSON object, but using "this.docnumber" from the parent object property returns "undefined", thus leading to an empty "acl" node.

var documentsJSON = [{
    "folder": "Enterprise1",
    "extension": "DOCX",
    "docnumber": "3912271",
    "version": "1"
  },
  {
    "folder": "Enterprise2",
    "extension": "MSG",
    "docnumber": "3912298",
    "version": "1"
  },
  {
    "folder": "Enterprise3",
    "extension": "DOCX",
    "docnumber": "3912692",
    "version": "1"
  }
]

var GroupsACLJSON = [{
    "docNumber": "3912271",
    "groupName": "group1"
  },
  {
    "docNumber": "3912271",
    "groupName": "group2"
  },
  {
    "docNumber": "3912298",
    "groupName": "group3"
  },
  {
    "docNumber": "3912298",
    "groupName": "group4"
  }
]

// importing and declaring xmlbuilder variable: 
var builder = require('xmlbuilder');
var xmlObjectImporter = builder.create('import', {
  version: '1.0',
  encoding: 'UTF-8',
  standalone: true
}, {
  headless: false,
  stringify: {}
});

var nodeArray = [];
var xmlObjectElement = {
  node: function() {
    for (var i = 0; i < documentsJSON.length; i++) {
      // populate the nodeObject for each row in documentsJSON and add it to the nodeArray:
      var nodeObject = {
        location: documentsJSON[i].folder,
        category: {
          attribute: [{
            '#text': documentsJSON[i].docnumber,
            '@name': "Document Number"
          }],
          '@name': "ACME",
        },
        docnumber: documentsJSON[i].docnumber,
        // loop through GroupsACLJSON to find if we have specific ACL groups for this document:
        acl: function() {
          var documentNumber = this.docnumber
          console.log(this.docnumber);
          var acl = [];
          var aclObject = {};
          for (var j = 0; j < GroupsACLJSON.length; j++) {
            if (GroupsACLJSON[j].docNumber == documentNumber) {
              aclObject = {
                '@group': GroupsACLJSON[j].groupName,
                '@permissions': '111111100'
              };
              acl.push(aclObject);
            };
          };
          return acl;
        },
        '@type': "document",
        '@action': "create",
      };
      nodeArray.push(nodeObject);
    };
    return nodeArray;
  }
};

// writing our elements in the xml file using the XML object:
var ele = xmlObjectImporter.ele(xmlObjectElement);

console.log(xmlObjectImporter.toString({
  pretty: true
}));

Here is an output I would expect from this:

<import>
  <node type="document" action="create">
    <location>Enterprise1</location>
    <category name="ACME">
      <attribute name="Document Number">3912271</attribute>
    </category>
    <docnumber>3912271</docnumber>
    <acl group="group1" permissions="111111100" />
    <acl group="group2" permissions="111111100" />
  </node>
  <node type="document" action="create">
    <location>Enterprise2</location>
    <category name="ACME">
      <attribute name="Document Number">3912298</attribute>
    </category>
    <docnumber>3912298</docnumber>
    <acl group="group3" permissions="111111100" />
    <acl group="group4" permissions="111111100" />
  </node>
  <node type="document" action="create">
    <location>Enterprise3</location>
    <category name="ACME">
      <attribute name="Document Number">3912692</attribute>
    </category>
    <docnumber>3912692</docnumber>
    <acl/>
  </node>
</import>

You have several undeclared variables that will cause your code to break when running in strict mode.

  1. i and j in your for loops both need declared. eg let i = 0 .
  2. The aclObject is not declared. You need to add a var declaration, eg const aclObject = { ... } .

After fixing those, I had no trouble running your code, at least, I had no trouble building the xmlObjectElement and executing the node() and acl() functions, which worked.

UPDATED

This will not fix the way that xml-builder is traversing your object and building the xml, but your functions could be improved by using Array methods instead of for loops. You'd have no need to use i or j and decrease the chances of introducing a bug for that reason.

For instance, you could easily replace both loops with a use of .map() . See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map .

var xmlObjectElement = {
  node: function () {
    return documentsJSON.map((document) => {
      // populate the nodeObject for each row in documentsJSON and add it to the nodeArray:
      return {
        location: document.folder,
        category: {
          attribute: [
            { '#text': document.docnumber, '@name': "Document Number" }
          ],
          '@name': "ACME",
        },
....
})

Following nxSolari's suggestion, I re-wrote the code using 2 functions instead of a big object and methods and got the desired result. I still don't understand how the code gets through the objects and methods, but here is the new working code:

    'use strict';

    var documentsJSON = [{
        "folder":"Enterprise1" , 
        "extension":"DOCX" , 
        "docnumber":"3912271" , 
        "version":"1"
        },
        {
        "folder":"Enterprise2" , 
        "extension":"MSG" , 
        "docnumber":"3912298" , 
        "version":"1"
        },
        {
        "folder":"Enterprise3" , 
        "extension":"DOCX" , 
        "docnumber":"3912692" , 
        "version":"1"
        }
    ]

    var GroupsACLJSON = [{
        "docNumber":"3912271" , 
        "groupName":"group1"
        },
        {
        "docNumber":"3912271" , 
        "groupName":"group2"
        },
        {
        "docNumber":"3912298" , 
        "groupName":"group3"
        },
        {
        "docNumber":"3912298" , 
        "groupName":"group4"
        },
        {
        "docNumber":"3912692" , 
        "groupName":"group5"
        }
    ]


    // importing and declaring xmlbuilder variable: 
    var builder = require('xmlbuilder');
    var xmlObjectImporter = builder.create('import', {
        version: '1.0', 
        encoding: 'UTF-8', 
        standalone: true
    }, {
        headless: false, 
        stringify: {}
    });

    var xmlObjectElement = {};

    function buildACLnode(passedDoc, acls) {
        var acl= [];
        for (var jDoc = 0 ; jDoc < acls.length ; jDoc++) {
            if (acls[jDoc].docNumber == passedDoc) {
                var aclObject = {
                    '@group':  acls[jDoc].groupName,
                    '@permissions': '111111100'
                };
                acl.push(aclObject);
            };
        };
        return acl;
    }

    function buildXML(documents) {
        var nodeArray = [];
        for (var iDoc = 0; iDoc < documents.length; iDoc++) {
            var nodeObject = {
                    node: {
                        location: documentsJSON[iDoc].folder,
                        category: {
                            attribute: [
                                { '#text': documentsJSON[iDoc].docnumber, '@name': "Document Number" }
                                ],
                            '@name': "ACME",
                        },
                        acl: buildACLnode(documentsJSON[iDoc].docnumber, GroupsACLJSON),
                        '@type': "document",
                        '@action': "create",
                        }
                };
            nodeArray.push(nodeObject);
        };
        return nodeArray;
    }

    xmlObjectElement = buildXML(documentsJSON);

    // writing our elements in the xml file using the XML object:
    var ele = xmlObjectImporter.ele(xmlObjectElement);

    console.log(xmlObjectImporter.toString({ 
        pretty: true 
    }));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM