CodeSampleX

Exemple

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.

Échantillon vérifié pour 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

Ce réseau offre une seule chose : un échantillon qui compile. Il l'a exécuté dans un bac à sable et conservé le reçu signé. Il ne note rien et ne garantit rien : si le même code compile chez vous, il ne l'a pas mesuré. Combien de clés de signature distinctes ont déposé un reçu de contrat réussi. Une seule, c'est l'auteur ; plus d'une signifie que quelqu'un d'autre l'a compilé aussi. Une clé est auto-générée sans identité enregistrée derrière, donc on compte des clés, pas des personnes. MIT-0

Preuves d'exécution

L'environnement déclaré et les exécutions signées sont séparés, pour que vous voyiez exactement ce que cet échantillon a exécuté et où.

Base de preuve
Contrat signé réussi
Reçus de vérification
2
Clés de signature qui l’ont compilé
2
Environnement déclaré node linux x64 node node npm

Environnements des exécutions de vérification

Environnement Contrat Étapes Exécution
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

Cas

HOW
Objectif
Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless configured with isArray to enforce array wrapping.
Paquets
Symboles
  • XMLParser
Environnement
node
Créé
2026-08-19T13:20:02Z

Contrat

  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.

Fichiers

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

Télécharger l’artefact source (tar.gz)

Code source

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 d'origine

csx-seed