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

Unable to assign attribute to nested node if already assigned higher-up #72

Closed
mcab opened this issue Feb 9, 2021 · 2 comments
Closed
Assignees
Labels
bug Something isn't working

Comments

@mcab
Copy link

mcab commented Feb 9, 2021

Describe the bug
I'm trying to assign a particular attribute (xmlns:ds) with the same key, value pairing, which has also been previously defined on a higher-level element. It applies correctly for the node closest to the root, but not for the lower nodes nodes.

To Reproduce

const { create } = require('xmlbuilder2');

function convertor(cert) {
    return {
        '@use': 'signing',
        'foobar': {
            '@xmlns:ds': 'att',
            'foobaz': {
                'foobarbaz': cert,
            }
        },
    }
}

function create_metadata(certs) {
    let final_certs = []
    for (cert in certs) {
        final_certs.push(convertor(certs[cert]))
    }

    xml = create({
        'foo': {
            '@xmlns:ds': 'att',
            'bar': {
                'baz': final_certs
            }
        }
    }).end({ prettyPrint: true })
    console.log(xml);
}

create_metadata(['cert1', 'cert2'])

Expected behavior
I expect each foobar to have @xmlns:ds as an attribute, but they do not.

The current output (2.4.0) looks like:

<?xml version="1.0"?>
<foo xmlns:ds="att">
  <bar>
    <baz use="signing">
      <foobar>
        <foobaz>
          <foobarbaz>cert1</foobarbaz>
        </foobaz>
      </foobar>
    </baz>
    <baz use="signing">
      <foobar>
        <foobaz>
          <foobarbaz>cert2</foobarbaz>
        </foobaz>
      </foobar>
    </baz>
  </bar>
</foo>

What I'm expecting:

<?xml version="1.0"?>
<foo xmlns:ds="att">
  <bar>
    <baz use="signing">
      <foobar xmlns:ds="att">
        <foobaz>
          <foobarbaz>cert1</foobarbaz>
        </foobaz>
      </foobar>
    </baz>
    <baz use="signing">
      <foobar xmlns:ds="att">
        <foobaz>
          <foobarbaz>cert2</foobarbaz>
        </foobaz>
      </foobar>
    </baz>
  </bar>
</foo>

Before passing to create(), the structure hints that the attribute should be set:

[
  {
    '@use': 'signing',
    foobar: {
      '@xmlns:ds': 'att',
      foobaz: [Object]
    }
  },
  {
    '@use': 'signing',
    foobar: {
      '@xmlns:ds': 'att',
      foobaz: [Object]
    }
  }
]

Version:

  • node.js: [12.4.1]
  • xmlbuilder2 [2.4.0]
@mcab
Copy link
Author

mcab commented Feb 9, 2021

Ah, it seems to be #20, but in reverse. 😅

Ideally, xmlns(:ds) is set on the child nodes too.

@oozcitak
Copy link
Owner

oozcitak commented Feb 10, 2021

This is not a bug but a feature of the serializer.

xmlbuilder2 keeps a record of namespaces while serializing the document. It can add, modify and even remove namespace prefixes. But it preserves the meaning of the document.

In your case, the parent foo element node declares the namespace att with the prefix ds. So, foo and all of its child elements have access to this namespace. Redeclaring the namespace under the child foobar element node is superfluous as it is already declared by foo. If you would canonicalize both documents you would see they are identical.

@oozcitak oozcitak closed this as completed Apr 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants