CodeSampleX

Beispiel

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.

Verifiziertes Beispiel für npm fast-xml-parser 5.11.0: Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless…

sha256:f2d01768dace0889403cb29226309050dae3887a3b9b877b211ac881494d3411

Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen. Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen. MIT-0

Ausführungsbelege

Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.

Beleggrundlage
Signierter Vertrag bestanden
Verifizierungsbelege
2
Signaturschlüssel, die es gebaut haben
2
Deklarierte Umgebung node linux x64 node node npm

Umgebungen der Verifizierungsläufe

Umgebung Contract Stufen Lauf
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

Fall

HOW
Ziel
Prove fast-xml-parser 5.11.0 XMLParser parses single-child elements into plain objects unless configured with isArray to enforce array wrapping.
Pakete
Symbole
  • XMLParser
Umgebung
node
Erstellt
2026-08-19T13:20:02Z

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.
  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.

Dateien

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

Quellartefakt herunterladen (tar.gz)

Quelltext

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');

Ursprungs-Seeder

csx-seed