123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- "use strict";
-
- const xnv = require("xml-name-validator");
-
- const { NAMESPACES } = require("./constants");
-
- function generatePrefix(map, newNamespace, prefixIndex) {
- const generatedPrefix = "ns" + prefixIndex;
- map[newNamespace] = [generatedPrefix];
- return generatedPrefix;
- }
-
- function preferredPrefixString(map, ns, preferredPrefix) {
- const candidateList = map[ns];
- if (!candidateList) {
- return null;
- }
- if (candidateList.includes(preferredPrefix)) {
- return preferredPrefix;
- }
- return candidateList[candidateList.length - 1];
- }
-
- function serializeAttributeValue(value/* , requireWellFormed*/) {
- if (value === null) {
- return "";
- }
- // TODO: Check well-formedness
- return value
- .replace(/&/g, "&")
- .replace(/"/g, """)
- .replace(/</g, "<")
- .replace(/>/g, ">")
- .replace(/\t/g, "	")
- .replace(/\n/g, "
")
- .replace(/\r/g, "
");
- }
-
- function serializeAttributes(
- element,
- map,
- localPrefixes,
- ignoreNamespaceDefAttr,
- requireWellFormed,
- refs
- ) {
- let result = "";
- const namespaceLocalnames = Object.create(null);
- for (const attr of element.attributes) {
- if (
- requireWellFormed &&
- namespaceLocalnames[attr.namespaceURI] &&
- namespaceLocalnames[attr.namespaceURI].has(attr.localName)
- ) {
- throw new Error("Found duplicated attribute");
- }
- if (!namespaceLocalnames[attr.namespaceURI]) {
- namespaceLocalnames[attr.namespaceURI] = new Set();
- }
- namespaceLocalnames[attr.namespaceURI].add(attr.localName);
- const attributeNamespace = attr.namespaceURI;
- let candidatePrefix = null;
- if (attributeNamespace !== null) {
- candidatePrefix = preferredPrefixString(
- map,
- attributeNamespace,
- attr.prefix
- );
- if (attributeNamespace === NAMESPACES.XMLNS) {
- if (
- attr.value === NAMESPACES.XML ||
- (attr.prefix === null && ignoreNamespaceDefAttr) ||
- (attr.prefix !== null &&
- localPrefixes[attr.localName] !== attr.value &&
- map[attr.value].includes(attr.localName))
- ) {
- continue;
- }
- if (requireWellFormed && attr.value === NAMESPACES.XMLNS) {
- throw new Error(
- "The XMLNS namespace is reserved and cannot be applied as an element's namespace via XML parsing"
- );
- }
- if (requireWellFormed && attr.value === "") {
- throw new Error(
- "Namespace prefix declarations cannot be used to undeclare a namespace"
- );
- }
- if (attr.prefix === "xmlns") {
- candidatePrefix = "xmlns";
- }
- } else if (candidatePrefix === null) {
- candidatePrefix = generatePrefix(
- map,
- attributeNamespace,
- refs.prefixIndex++
- );
- result += ` xmlns:${candidatePrefix}="${serializeAttributeValue(
- attributeNamespace,
- requireWellFormed
- )}"`;
- }
- }
-
- result += " ";
- if (candidatePrefix !== null) {
- result += candidatePrefix + ":";
- }
- if (
- requireWellFormed &&
- (attr.localName.includes(":") ||
- !xnv.name(attr.localName) ||
- (attr.localName === "xmlns" && attributeNamespace === null))
- ) {
- throw new Error("Invalid attribute localName value");
- }
- result += `${attr.localName}="${serializeAttributeValue(
- attr.value,
- requireWellFormed
- )}"`;
- }
- return result;
- }
-
- module.exports.preferredPrefixString = preferredPrefixString;
- module.exports.generatePrefix = generatePrefix;
- module.exports.serializeAttributeValue = serializeAttributeValue;
- module.exports.serializeAttributes = serializeAttributes;
|