Example #1
0
/*
    Handle all core operators. We currenly handle only === and !==
    TODO. Must implement: +, -, <, >, <=, >=, ==, ===, !=, !==, &, |
 */
static EjsObj *invokeOperator(Ejs *ejs, EjsXML *lhs, int opCode,  EjsXML *rhs)
{
    EjsObj      *l, *r;
    bool        boolResult;

    assure(ejsIsXML(ejs, lhs));
    assure(ejsIsXML(ejs, rhs));

    //  TODO - Complete
    switch (opCode) {
    case EJS_OP_COMPARE_EQ:
    case EJS_OP_COMPARE_STRICTLY_EQ:
        boolResult = (lhs == rhs);
        break;

    case EJS_OP_COMPARE_NE:
    case EJS_OP_COMPARE_STRICTLY_NE:
        boolResult = !(lhs == rhs);
        break;

    default:
        /*
            Cast to strings and re-invoke
         */
        l = ejsCast(ejs, lhs, String);
        r = ejsCast(ejs, rhs, String);
        return ejsInvokeOperator(ejs, l, opCode, r);
    }
    return (EjsObj*) ejsCreateBoolean(ejs, boolResult);
}
Example #2
0
/*
    native function XML(value: Object = null)
 */
static EjsObj *xmlConstructor(Ejs *ejs, EjsXML *thisObj, int argc, EjsObj **argv)
{
    EjsObj      *arg, *vp;
    wchar       *str;

    //  TODO - should be also able to handle a File object

    if (thisObj == 0) {
        /*
            Called as a function - cast the arg
         */
        if (argc > 0) {
            if ((arg = ejsCast(ejs, argv[0], String)) == 0) {
                return 0;
            }
        }
        thisObj = ejsCreateXML(ejs, 0, N(NULL, NULL), NULL, NULL);
    }
    if (argc == 0) {
        return (EjsObj*) thisObj;
    }

    arg = argv[0];
    assert(arg);

    if (!ejsIsDefined(ejs, arg)) {
        return (EjsObj*) thisObj;
    }
    arg = ejsCast(ejs, argv[0], String);
    if (arg && ejsIs(ejs, arg, String)) {
        str = ((EjsString*) arg)->value;
        if (str == 0) {
            return 0;
        }
        while (isspace((uchar) *str)) str++;
        if (*str == '<') {
            /* XML Literal */
            ejsLoadXMLString(ejs, thisObj, (EjsString*) arg);

        } else {
            /* Load from file */
            loadXml(ejs, thisObj, argc, argv);
        }
    } else if (arg && ejsIsXML(ejs, arg)) {
        if ((vp = xmlToString(ejs, argv[0], 0, NULL)) != 0) {
            ejsLoadXMLString(ejs, thisObj, (EjsString*) vp);
        }

    } else {
        ejsThrowArgError(ejs, "Bad type passed to XML constructor");
        return 0;
    }
    return (EjsObj*) thisObj;
}
Example #3
0
/*
    Create a value node. If the value is an XML node already, we are done. Otherwise, cast the value to a string
    and create a text child node containing the string value.
 */
static EjsXML *createValueNode(Ejs *ejs, EjsXML *elt, EjsObj *value)
{
    EjsXML      *text;
    EjsString   *str;

    if (ejsIsXML(ejs, value)) {
        return (EjsXML*) value;
    }
    if ((str = (EjsString*) ejsCast(ejs, value, String)) == NULL) {
        return 0;
    }
    if (mprGetListLength(elt->elements) == 1) {
        /*
            Update an existing text element
         */
        text = mprGetFirstItem(elt->elements);
        if (text->kind == EJS_XML_TEXT) {
            text->value = str;
            return elt;
        }
    }

    /*
        Create a new text element
     */
    if (str->value[0] != '\0') {
        text = ejsCreateXML(ejs, EJS_XML_TEXT, N(NULL, NULL), elt, str);
        elt = ejsAppendToXML(ejs, elt, text);
    }
    return elt;
}
Example #4
0
/*
    Update an existing element
 */
static int updateElement(Ejs *ejs, EjsXML *list, EjsXML *elt, int index, EjsObj *value)
{
    EjsXML      *node;
    int         i, j;

    if (!ejsIsXML(ejs, value)) {
        /* Not XML or XMLList -- convert to string */
        value = ejsCast(ejs, value, String);                //  TODO - seem to be doing this in too many places
    }
    mprSetItem(list->elements, index, value);

    if (elt->kind == EJS_XML_ATTRIBUTE) {
        assure(ejsIs(ejs, value, String));
        i = mprLookupItem(elt->parent->elements, elt);
        assure(i >= 0);
        ejsSetXMLElement(ejs, elt->parent, i, elt);
        //  TODO - why do this. Doesn't above do this?
        ejsSetPropertyByName(ejs, elt->parent, elt->qname, value);
        elt->value = (EjsString*) value;
    }

    if (ejsIsXML(ejs, value) && ((EjsXML*) value)->kind == EJS_XML_LIST) {
        value = (EjsObj*) shallowCopy(ejs, (EjsXML*) value);
        if (elt->parent) {
            index = mprLookupItem(elt->parent->elements, elt);
            assure(index >= 0);
            for (j = 0; j < mprGetListLength(((EjsXML*) value)->elements); j++) {
                mprInsertItemAtPos(elt->parent->elements, index, value);
            }
        }

    } else if (ejsIsXML(ejs, value) || elt->kind != EJS_XML_ELEMENT) {
        if (elt->parent) {
            index = mprLookupItem(elt->parent->elements, elt);
            assure(index >= 0);
            mprSetItem(elt->parent->elements, index, value);
            ((EjsXML*) value)->parent = elt->parent;
            if (ejsIs(ejs, value, String)) {
                node = ejsCreateXML(ejs, EJS_XML_TEXT, N(NULL, NULL), list, (EjsString*) value);
                mprSetItem(list->elements, index, node);
            } else {
                mprSetItem(list->elements, index, value);
            }
        }

    } else {
        ejsSetPropertyByName(ejs, elt, N(NULL, "*"), value);
    }
    return index;
}
Example #5
0
/*
    Set a property by name
    There are 7 kinds of qname's: prop, @att, [prop], *, @*, .name, .@name
 */
static int setXmlPropertyByName(Ejs *ejs, EjsXML *xml, EjsName qname, EjsObj *value)
{
    EjsXML      *elt, *xvalue, *rp, *lastElt;
    EjsObj      *originalValue;
    int         index, last;

    last = 0;
    lastElt = 0;

    if (isdigit((uchar) qname.name->value[0]) && allDigitsForXml(qname.name)) {
        ejsThrowTypeError(ejs, "Integer indicies for set are not allowed");
        return EJS_ERR;
    }

    if (xml->kind != EJS_XML_ELEMENT) {
        //  TODO spec requires this -- but why? -- surely throw?
        return 0;
    }

    /*
        Massage the value type.
     */
    originalValue = value;

    xvalue = (EjsXML*) value;
    if (ejsIsXML(ejs, xvalue)) {
        if (xvalue->kind == EJS_XML_LIST) {
            value = cloneXml(ejs, xvalue, 1);

        } else if (xvalue->kind == EJS_XML_TEXT || xvalue->kind == EJS_XML_ATTRIBUTE) {
            value = ejsCast(ejs, originalValue, String);

        } else {
            value = cloneXml(ejs, xvalue, 1);
        }
    } else {
        value = ejsCast(ejs, value, String);
    }
    if (qname.name->value[0] == '@') {
        return setXmlPropertyAttributeByName(ejs, xml, qname, value);
    }
    /*
        Delete redundant elements by the same name.
     */
    if (xml->elements) {
        for (last = -1, index = -1; (elt = mprGetPrevItem(xml->elements, &index)) != 0; ) {
            if (qname.name->value[0] == '*' || (elt->kind == EJS_XML_ELEMENT && elt->qname.name == qname.name)) {
                /*
                    Must remove all redundant elements of the same name except the first one
                 */
                if (last >= 0) {
                    rp = mprGetItem(xml->elements, last);
                    rp->parent = 0;
                    mprRemoveItemAtPos(xml->elements, last);
                }
                last = index;
                lastElt = elt;
            }
        }
    }
    if (xml->elements == 0) {
        //  TODO - need routine to do this centrally so we can control the default number of elements in the list?
        xml->elements = mprCreateList(-1, 0);
    }
    elt = lastElt;
    index = last;

    if (qname.name->value[0] == '*') {
        /*
            Special case when called from XMLList to update the value of an element
         */
        xml = createValueNode(ejs, xml, value);

    } else if (elt == 0) {
        /*
            Not found. New node required.
         */
        elt = ejsCreateXML(ejs, EJS_XML_ELEMENT, qname, xml, NULL);
        if (elt == 0) {
            return 0;
        }
        index = mprGetListLength(xml->elements);
        xml = ejsAppendToXML(ejs, xml, createValueNode(ejs, elt, value));

    } else {
        /*
            Update existing element.
         */
        xml = ejsSetXMLElement(ejs, xml, index, createValueNode(ejs, elt, value));
    }

    if (xml == 0) {
        return EJS_ERR;
    }
    return index;
}
Example #6
0
/*
    Set a property attribute by name.
 */
static int setXmlPropertyAttributeByName(Ejs *ejs, EjsXML *xml, EjsName qname, EjsObj *value)
{
    EjsXML      *elt, *attribute, *xvalue, *lastElt;
    EjsString   *sv;
    EjsName     qn;
    wchar       *str;
    int         index, last, next;

    /*
        Attribute. If the value is an XML list, convert to a space separated string
     */
    xvalue = (EjsXML*) value;
    if (ejsIsXML(ejs, xvalue) && xvalue->kind == EJS_XML_LIST) {
        str = 0;
        for (next = 0; (elt = mprGetNextItem(xvalue->elements, &next)) != 0; ) {
            sv = (EjsString*) ejsCast(ejs, (EjsObj*) elt, String);
            str = mrejoin(str, NULL, " ", sv->value, NULL);
        }
        value = (EjsObj*) ejsCreateString(ejs, str, -1);

    } else {
        value = ejsCast(ejs, value, String);
    }
    assert(ejsIs(ejs, value, String));

    /*
        Find the first attribute that matches. Delete all other attributes of the same name.
     */
    index = 0;
    if (xml->attributes) {
        lastElt = 0;
        for (last = -1, index = -1; (elt = mprGetPrevItem(xml->attributes, &index)) != 0; ) {
            assert(qname.name->value[0] == '@');
            if (wcmp(elt->qname.name->value, &qname.name->value[1]) == 0) {
                if (last >= 0) {
                    mprRemoveItemAtPos(xml->attributes, last);
                }
                last = index;
                lastElt = elt;
            }
        }
        if (lastElt) {
            /*
                Found a match. So replace its value
             */
            lastElt->value = (EjsString*) value;
            return last;

        } else {
            index = mprGetListLength(xml->attributes);
        }
    }
    //  TODO - namespace work to do here

    /*
        Not found. Create a new attribute node
     */
    assert(ejsIs(ejs, value, String));
    qn.space = NULL;
    qn.name = ejsSubstring(ejs, qname.name, 1, -1);
    attribute = ejsCreateXML(ejs, EJS_XML_ATTRIBUTE, qn, xml, (EjsString*) value);
    if (xml->attributes == 0) {
        xml->attributes = mprCreateList(-1, 0);
    }
    mprSetItem(xml->attributes, index, attribute);
    return index;
}