Files
shaka-player/lib/dash/json_utils.js
T
Álvaro Velad Galván 4f62ce8b24 build: Reduce bundle size by deduplicating license headers (#10182)
Ensure generated bundles contain a single license header instead of
repeating the same notice across bundled modules.

Normalize all copyright years to 2016 and remove
duplicate license headers from generated bundles.

This reduces the final bundle size while preserving license information
in the distributed artifacts.
2026-06-05 12:43:28 +02:00

202 lines
5.8 KiB
JavaScript

/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
// cspell:ignore subk subv
goog.provide('shaka.dash.JsonUtils');
goog.require('shaka.util.StringUtils');
/**
* @summary JSON processing utility functions.
*/
shaka.dash.JsonUtils = class {
/**
* Converts a DASH-JSON manifest (dash-json-schema) into an MPD XML string.
*
* @param {!Object} json - Root JSON object following dash-json-schema.
* @return {string}
*/
static jsonToMpd(json) {
const MPD_NS = 'urn:mpeg:dash:schema:mpd:2011';
/**
* Emit a tag with attributes and content.
*
* @param {string} tagName
* @param {!Object<string, ?>} attrs
* @param {string} inner
* @return {string}
*/
function emit(tagName, attrs, inner) {
let out = '<' + tagName;
for (const [k, v] of Object.entries(attrs)) {
out += ` ${k}="${shaka.util.StringUtils.htmlUnescape(v)}"`;
}
if (inner === '') {
return out + '/>';
}
return out + '>' + inner + `</${tagName}>`;
}
/**
* Recursively build XML for a JSON node.
*
* @param {string} key Element name, WITHOUT prefix
* @param {*} node Value
* @param {!Object} nsMap Map prefix->URI
* @return {string}
*/
function buildNode(key, node, nsMap) {
if (node == null) {
return emit(key, {}, '');
}
// Primitive → <key>value</key>
if (typeof node !== 'object') {
return emit(key, {}, shaka.util.StringUtils.htmlUnescape(String(node)));
}
// Object case
const attrs = {};
let textContent = '';
const children = [];
// Handle prefix groups (namespaced stuff)
const obj = /** @type {!Object<string,?>} */ (node);
for (const [k, v] of Object.entries(obj)) {
if (k === '$value' || k === '$ns') {
continue;
}
const isPrefixGroup = nsMap[k] !== undefined;
if (isPrefixGroup && typeof v === 'object' && v != null) {
const prefix = k;
const groupObj = v;
for (const [subk, subv] of Object.entries(groupObj)) {
if (Array.isArray(subv)) {
// Namespaced repeating child elements <prefix:subk>
for (const item of subv) {
const tag = `${prefix}:${subk}`;
children.push(buildNode(tag, item, nsMap));
}
} else if (typeof subv === 'object') {
// Single namespaced child element
const tag = `${prefix}:${subk}`;
children.push(buildNode(tag, subv, nsMap));
} else {
// Namespaced attribute prefix:attr
attrs[`${prefix}:${subk}`] = subv;
}
}
continue;
}
// Regular attribute / child element
const val = v;
const isObj = typeof val === 'object' && val != null;
if (!isObj) {
// scalar → attribute
attrs[k] = val;
} else {
// object or array → child
if (Array.isArray(val)) {
for (const item of val) {
children.push(buildNode(k, item, nsMap));
}
} else {
children.push(buildNode(k, val, nsMap));
}
}
}
if (node['$value'] !== undefined && node['$value'] !== null) {
textContent = shaka.util.StringUtils.htmlUnescape(node['$value']);
}
return emit(key, attrs, textContent + children.join(''));
}
// ------------------------------------------------------------------
// Build namespace map prefix→URI from $ns
// ------------------------------------------------------------------
const nsMap = {};
if (json['$ns'] && typeof json['$ns'] === 'object') {
for (const [uri, info] of Object.entries(json['$ns'])) {
const prefix = info.prefix;
nsMap[prefix] = uri;
}
}
// ------------------------------------------------------------------
// Build root attributes: xmlns + xmlns:pref + scalar attrs at root
// ------------------------------------------------------------------
const rootAttrs = {
'xmlns': MPD_NS,
};
// nsMap: prefix→uri
for (const [prefix, uri] of Object.entries(nsMap)) {
rootAttrs[`xmlns:${prefix}`] = uri;
}
// Non-object root attributes
for (const [k, v] of Object.entries(json)) {
if (k === '$ns') {
continue;
}
if (typeof v !== 'object' || v === null) {
rootAttrs[k] = v;
}
}
// ------------------------------------------------------------------
// Build children of <MPD>
// ------------------------------------------------------------------
let mpdInner = '';
for (const [k, v] of Object.entries(json)) {
if (k === '$ns') {
continue;
}
if (k in nsMap) {
// Namespace group
const groupObj = /** @type {!Object<string,?>} */ (v);
for (const [subk, subv] of Object.entries(groupObj)) {
if (Array.isArray(subv)) {
for (const item of subv) {
const tag = `${k}:${subk}`;
mpdInner += buildNode(tag, item, nsMap);
}
} else if (typeof subv === 'object') {
const tag = `${k}:${subk}`;
mpdInner += buildNode(tag, subv, nsMap);
} else {
// namespaced attribute on root? (rare)
rootAttrs[`${k}:${subk}`] = subv;
}
}
continue;
}
if (typeof v === 'object' && v !== null) {
if (Array.isArray(v)) {
for (const item of v) {
mpdInner += buildNode(k, item, nsMap);
}
} else {
mpdInner += buildNode(k, v, nsMap);
}
}
}
return emit('MPD', rootAttrs, mpdInner);
}
};