CodeSampleX

Exemplo

fast-xml-parser 5.11.0: Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless configured with isArray to enforce array wrapping.

Amostra verificada para npm fast-xml-parser 5.11.0: Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless configured…

sha256:f2d01768dace0889403cb29226309050dae3887a3b9b877b211ac881494d3411

Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu. Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas. MIT-0

Evidência de execução

O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.

Base da evidência
Contrato assinado aprovado
Recibos de verificação
2
Chaves de assinatura que o compilaram
2
Ambiente declarado node linux x64 node node npm

Ambientes das execuções de verificação

Ambiente Contrato Etapas Execução
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-19
node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-19

Caso

HOW
Objetivo
Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless configured with isArray to enforce array wrapping.
Pacotes
Símbolos
  • XMLParser
Ambiente
node
Criado
2026-08-19T13:20:02Z

Contrato

  1. XMLParser parses single-child elements into plain objects rather than 1-element arrays by default, causing array methods like map to throw TypeError, unless the isArray callback explicitly returns true for the tag or jPath.
  2. An XML document with multiple same-name sibling tags produces an Array by default without requiring the isArray option.
  3. The isArray callback receives tagName, jPath, isLeafNode, and isAttribute arguments during parsing to selectively enforce array wrapping.
  4. When isAttribute is true, the isArray callback forces attribute values into single-element arrays.
  5. Single-element nodes configured via isArray maintain array methods like map and filter without requiring runtime type guards.

Arquivos

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • test/contract.mjs

Baixar o artefato de código-fonte (tar.gz)

Código-fonte

NOTES.md
# fast-xml-parser XMLParser Array Handling Configuration

## Prior Search Result
`search_known_solution` returned `miss: true` (no prior verified sample found for this library and configuration target).

## Exact Release Pinned
- `fast-xml-parser` pinned to `5.11.0`.

## Observed Behaviour and Failure Mode
Because XML does not have a native array data type, parser libraries infer multiplicity based on sibling tag repetition. By default, `XMLParser` converts elements appearing multiple times into a JavaScript Array, but collapses single-instance elements into a plain Object or primitive value.

When downstream code expects a collection (such as iterating over entries with `.map()` or `.filter()`), this default behavior fails loudly at runtime:
- In tests containing multiple entries (`<feed><entry>...</entry><entry>...</entry></feed>`), `parsed.feed.entry` is an Array and methods like `parsed.feed.entry.map(...)` succeed.
- In production when receiving a payload with exactly one entry (`<feed><entry>...</entry></feed>`), `parsed.feed.entry` is a plain Object, causing an immediate runtime crash: `TypeError: parsed.feed.entry.map is not a function`.

Configuring the `isArray` option:
```javascript
const parser = new XMLParser({
  isArray: (tagName, jPath, isLeafNode, isAttribute) => {
    return jPath === 'feed.entry';
  }
});
```
instructs the parser to consistently wrap single-instance nodes matching the predicate into single-element arrays (`[entry]`), ensuring uniform array handling across all payload sizes.
csx.json
{"case":{"believed":"XMLParser automatically creates an Array for repeated schema elements regardless of whether the document contains one or multiple child tags.","caseId":"case:sha256:b30c93adc45d5ff87be42f7b7d4c250b1611df22e0bcd5d0b7bc9c395b88afee","contract":["XMLParser parses single-child elements into plain objects rather than 1-element arrays by default, causing array methods like map to throw TypeError, unless the isArray callback explicitly returns true for the tag or jPath.","An XML document with multiple same-name sibling tags produces an Array by default without requiring the isArray option.","The isArray callback receives tagName, jPath, isLeafNode, and isAttribute arguments during parsing to selectively enforce array wrapping.","When isAttribute is true, the isArray callback forces attribute values into single-element arrays.","Single-element nodes configured via isArray maintain array methods like map and filter without requiring runtime type guards."],"goal":"Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless configured with isArray to enforce array wrapping.","kind":"HOW","packages":["pkg:npm/fast-xml-parser@5.11.0"],"schemaVersion":1,"symbols":["XMLParser"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/fast-xml-parser@5.11.0"],"schemaVersion":1,"symbols":["XMLParser"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "sample",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "sample",
      "version": "1.0.0",
      "dependencies": {
        "fast-xml-parser": "5.11.0"
      }
    },
    "node_modules/@nodable/entities": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz",
      "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/nodable"
        }
      ],
      "license": "MIT"
    },
    "node_modules/anynum": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz",
      "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT"
    },
    "node_modules/fast-xml-builder": {
      "version": "1.3.1",
      "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.1.tgz",
      "integrity": "sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "path-expression-matcher": "^1.6.2",
        "xml-naming": "^0.3.0"
      }
    },
    "node_modules/fast-xml-parser": {
      "version": "5.11.0",
      "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.11.0.tgz",
      "integrity": "sha512-9IGxMqvqLOnqP+Egi1nqDHKv5k8aZ7r9n558enxcucmyVGEBNPAU+MOg/8jPIS7rO7sSq4gFm1/nHtiaubMruw==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "@nodable/entities": "^3.0.0",
        "fast-xml-builder": "^1.2.0",
        "is-unsafe": "^2.0.0",
        "path-expression-matcher": "^1.6.2",
        "strnum": "^2.4.2",
        "xml-naming": "^0.3.0"
      },
      "bin": {
        "fxparser": "src/cli/cli.js"
      }
    },
    "node_modules/is-unsafe": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.2.tgz",
      "integrity": "sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT"
    },
    "node_modules/path-expression-matcher": {
      "version": "1.6.2",
      "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz",
      "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT",
      "engines": {
        "node": ">=14.0.0"
      }
    },
    "node_modules/strnum": {
      "version": "2.4.2",
      "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.2.tgz",
      "integrity": "sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "anynum": "^1.0.1"
      }
    },
    "node_modules/xml-naming": {
      "version": "0.3.0",
      "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz",
      "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/NaturalIntelligence"
        }
      ],
      "license": "MIT",
      "engines": {
        "node": ">=16.0.0"
      }
    }
  }
}
package.json
{
  "name": "sample",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "fast-xml-parser": "5.11.0"
  }
}
test/contract.mjs
import assert from 'node:assert';
import { XMLParser } from 'fast-xml-parser';

// Contract 1: XMLParser parses single-child elements into plain objects rather than 1-element arrays by default,
// causing array methods like map to throw TypeError, unless the isArray callback explicitly returns true for the tag or jPath.
const singleXml = '<feed><entry><id>101</id><title>Item 1</title></entry></feed>';
const defaultParser = new XMLParser({ ignoreAttributes: false });
const defaultSingleResult = defaultParser.parse(singleXml);

assert.strictEqual(Array.isArray(defaultSingleResult.feed.entry), false);
assert.strictEqual(typeof defaultSingleResult.feed.entry, 'object');
assert.strictEqual(defaultSingleResult.feed.entry.id, 101);
assert.strictEqual(defaultSingleResult.feed.entry.title, 'Item 1');

assert.throws(
  () => {
    defaultSingleResult.feed.entry.map(item => item.id);
  },
  {
    name: 'TypeError'
  }
);

// Contract 2: An XML document with multiple same-name sibling tags produces an Array by default without requiring the isArray option.
const multiXml = '<feed><entry><id>101</id><title>Item 1</title></entry><entry><id>102</id><title>Item 2</title></entry></feed>';
const defaultMultiResult = defaultParser.parse(multiXml);

assert.strictEqual(Array.isArray(defaultMultiResult.feed.entry), true);
assert.strictEqual(defaultMultiResult.feed.entry.length, 2);
assert.strictEqual(defaultMultiResult.feed.entry[0].id, 101);
assert.strictEqual(defaultMultiResult.feed.entry[1].id, 102);
assert.deepStrictEqual(defaultMultiResult.feed.entry.map(item => item.id), [101, 102]);

// Contract 3: The isArray callback receives tagName, jPath, isLeafNode, and isAttribute arguments during parsing to selectively enforce array wrapping.
const capturedInvocations = [];
const configuredParser = new XMLParser({
  ignoreAttributes: false,
  isArray: (tagName, jPath, isLeafNode, isAttribute) => {
    capturedInvocations.push({ tagName, jPath, isLeafNode, isAttribute });
    return jPath === 'feed.entry' || (isAttribute === true && tagName === '@_tags');
  }
});

const configuredSingleResult = configuredParser.parse(singleXml);

assert.strictEqual(Array.isArray(configuredSingleResult.feed.entry), true);
assert.strictEqual(configuredSingleResult.feed.entry.length, 1);
assert.strictEqual(configuredSingleResult.feed.entry[0].id, 101);

const entryInvocation = capturedInvocations.find(inv => inv.tagName === 'entry');
assert.ok(entryInvocation !== undefined, 'isArray was invoked for entry tag');
assert.strictEqual(entryInvocation.jPath, 'feed.entry');
assert.strictEqual(entryInvocation.isLeafNode, false);
assert.strictEqual(entryInvocation.isAttribute, undefined);

// Contract 4: When isAttribute is true, the isArray callback forces attribute values into single-element arrays.
const attributeXml = '<item category="books" tags="fiction"/>';
const attributeResult = configuredParser.parse(attributeXml);

assert.strictEqual(attributeResult.item['@_category'], 'books');
assert.strictEqual(Array.isArray(attributeResult.item['@_tags']), true);
assert.strictEqual(attributeResult.item['@_tags'].length, 1);
assert.deepStrictEqual(attributeResult.item['@_tags'], ['fiction']);

// Contract 5: Single-element nodes configured via isArray maintain array methods like map and filter without requiring runtime type guards.
const configuredMultiResult = configuredParser.parse(multiXml);

assert.strictEqual(Array.isArray(configuredMultiResult.feed.entry), true);
assert.strictEqual(configuredMultiResult.feed.entry.length, 2);

const singleMapped = configuredSingleResult.feed.entry.map(entry => entry.id);
const multiMapped = configuredMultiResult.feed.entry.map(entry => entry.id);
const singleFiltered = configuredSingleResult.feed.entry.filter(entry => entry.id === 101);

assert.deepStrictEqual(singleMapped, [101]);
assert.deepStrictEqual(multiMapped, [101, 102]);
assert.strictEqual(singleFiltered.length, 1);
assert.strictEqual(singleFiltered[0].title, 'Item 1');

Seeder de origem

csx-seed