| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /** |
| * Functions to help represent data as lists of elements and attributes. |
| */ |
| |
| var element = "'element" |
| var attribute = "'attribute" |
| var atsign = "'@" |
| |
| /** |
| * Return true if a value is an element. |
| */ |
| function isElement(v) { |
| return (!(!isList(v) || isNull(v) || car(v) != element)); |
| } |
| |
| /** |
| * Return true if a value is an attribute. |
| */ |
| function isAttribute(v) { |
| return (!(!isList(v) || isNull(v) || car(v) != attribute)); |
| } |
| |
| /** |
| * Return the name of an attribute. |
| */ |
| attributeName = cadr; |
| |
| /** |
| * Return the value of an attribute. |
| */ |
| attributeValue = caddr; |
| |
| /** |
| * Return the name of an element. |
| */ |
| elementName = cadr; |
| |
| /** |
| * Return true if an element has children. |
| */ |
| function elementHasChildren(l) { |
| return !isNull(cddr(l)); |
| } |
| |
| /** |
| * Return the children of an element. |
| */ |
| elementChildren = cddr; |
| |
| /** |
| * Return true if an element has a value. |
| */ |
| function elementHasValue(l) { |
| var r = reverse(l); |
| if (isSymbol(car(r))) |
| return false; |
| return (!(isList(car(r)) && !isNull(car(r)) && isSymbol(car(car(r))))) |
| } |
| |
| /** |
| * Return the value of an element. |
| */ |
| function elementValue(l) { |
| return car(reverse(l)); |
| } |
| |
| /** |
| * Convert an element to a value. |
| */ |
| function elementToValueIsList(v) { |
| if (!isList(v)) |
| return false; |
| return isNull(v) || !isSymbol(car(v)); |
| } |
| |
| function elementToValue(t) { |
| if (isTaggedList(t, attribute)) |
| return mklist(atsign + attributeName(t).substring(1), attributeValue(t)); |
| if (isTaggedList(t, element)) { |
| if (elementHasValue(t)) { |
| if (!elementToValueIsList(elementValue(t))) |
| return mklist(elementName(t), elementValue(t)); |
| return cons(elementName(t), mklist(elementsToValues(elementValue(t)))); |
| } |
| return cons(elementName(t), elementsToValues(elementChildren(t))); |
| } |
| if (!isList(t)) |
| return t; |
| return elementsToValues(t); |
| } |
| |
| /** |
| * Convert a list of elements to a list of values. |
| */ |
| function elementToValueIsSymbol(v) { |
| return (!(!isList(v)) || isNull(v) || !isSymbol(car(v))); |
| } |
| |
| function elementToValueGroupValues(v, l) { |
| if (isNull(l) || !elementToValueIsSymbol(v) || !elementToValueIsSymbol(car(l))) |
| return cons(v, l); |
| if (car(car(l)) != car(v)) |
| return cons(v, l); |
| if (!elementToValueIsList(cadr(car(l)))) { |
| var g = mklist(car(v), mklist(cdr(v), cdr(car(l)))); |
| return elementToValueGroupValues(g, cdr(l)); |
| } |
| var g = mklist(car(v), cons(cdr(v), cadr(car(l)))); |
| return elementToValueGroupValues(g, cdr(l)); |
| } |
| |
| function elementsToValues(e) { |
| if (isNull(e)) |
| return e; |
| return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e))); |
| } |
| |
| /** |
| * Convert a value to an element. |
| */ |
| function valueToElement(t) { |
| if (isList(t) && !isNull(t) && isSymbol(car(t))) { |
| var n = car(t); |
| var v = isNull(cdr(t))? mklist() : cadr(t); |
| if (!isList(v)) { |
| if (n.substring(0, 2) == atsign) |
| return mklist(attribute, "'" + n.substring(2), v); |
| return mklist(element, n, v); |
| } |
| if (isNull(v) || !isSymbol(car(v))) |
| return cons(element, cons(n, mklist(valuesToElements(v)))); |
| return cons(element, cons(n, valuesToElements(cdr(t)))); |
| } |
| if (!isList(t)) |
| return t; |
| return valuesToElements(t); |
| } |
| |
| /** |
| * Convert a list of values to a list of elements. |
| */ |
| function valuesToElements(l) { |
| if (isNull(l)) |
| return l; |
| return cons(valueToElement(car(l)), valuesToElements(cdr(l))); |
| } |
| |
| /** |
| * Return a selector lambda function which can be used to filter elements. |
| */ |
| function selector(s) { |
| function evalSelect(s, v) { |
| if (isNull(s)) |
| return true; |
| if (isNull(v)) |
| return false; |
| if (car(s) != car(v)) |
| return false; |
| return evalSelect(cdr(s), cdr(v)); |
| } |
| |
| return function(v) { return evalSelect(s, v); }; |
| } |
| |
| /** |
| * Return the attribute with the given name. |
| */ |
| function namedAttribute(name, l) { |
| return memo(l, name, function() { |
| var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l); |
| if (isNull(f)) |
| return null; |
| return car(f); |
| }); |
| } |
| |
| /** |
| * Return the value of the attribute with the given name. |
| */ |
| function namedAttributeValue(name, l) { |
| var a = namedAttribute(name, l); |
| if (a == null) |
| return null |
| return attributeValue(a); |
| } |
| |
| /** |
| * Return child elements with the given name. |
| */ |
| function namedElementChildren(name, l) { |
| return memo(l, name, function() { |
| return filter(function(v) { return isElement(v) && elementName(v) == name; }, l); |
| }); |
| } |
| |
| /** |
| * Return the child element with the given name. |
| */ |
| function namedElementChild(name, l) { |
| var f = namedElementChildren(name, l); |
| if (isNull(f)) |
| return null; |
| return car(f); |
| } |
| |
| /** |
| * Side effect functions. Use with moderation. |
| */ |
| |
| /** |
| * Set the contents of an element. |
| */ |
| function setElement(l, e) { |
| setlist(l, e); |
| l.memo = {}; |
| } |
| |