📄 ejsxml.c
字号:
} return ejsGetVarPtr(pp);}/******************************************************************************//* NEWstatic EjsVar *setXmlProperty(Ejs *ep, EjsVar *op, const char *property, EjsVar *value){ if ((value->objectState->baseClass != XML && value->objectState->baseClass != XMLList) || value->string[0] != '<') { ejsVarToString(luevalue.toString(); ejsRunMethod(ep, value, "toString", 0); value = ejsDupVar(ep->result); } else { value = ejsDupVar(value); } if (isdigit(*property)) { // ERROR -- reserved for future versions return 0; } if (*property == '@') { if (op->objectState->baseClass == XMLList) { if (op->obj.LENGTH_PROPERTY == 0) { c = ""; } else { // Catenate all result of toString on all elts in list } } else { c = c.toString(); } // Replace existing attribute of same name or insert return; } for (i = op->obj.LENGTH - 1; i >= 0; i--) { // Delete item of same name } if (not Found) { Append new Xml object - set [[name]], [[class]] == "element" } mprFree(value);} *//******************************************************************************//************************************ Methods *********************************//******************************************************************************/static int load(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv){ const char *fileName; XmlState *parser; Exml *xp; MprFile *file; if (argc != 1 || !ejsVarIsString(argv[0])) { ejsError(ep, EJS_ARG_ERROR, "Bad args. Usage: load(fileName);"); return -1; } fileName = argv[0]->string; /* MOB -- not romable Need rom code in MPR not MprServices */ file = mprOpen(ep, fileName, O_RDONLY, 0664); if (file == 0) { ejsError(ep, EJS_IO_ERROR, "Can't open: %s", fileName); return -1; } /* MOB -- should we empty thisObj of all existing properties ? */ xp = initParser(ep, thisObj, fileName); parser = exmlGetParseArg(xp); exmlSetInputStream(xp, readFileData, (void*) file); if (exmlParse(xp) < 0) { if (! ejsGotException(ep)) { ejsError(ep, EJS_IO_ERROR, "Can't parse XML file: %s\nDetails %s", fileName, exmlGetErrorMsg(xp)); } termParser(xp); mprClose(file); return -1; } ejsSetReturnValue(ep, parser->nodeStack[0].obj); termParser(xp); mprClose(file); return 0;}/******************************************************************************/static int loadXmlString(Ejs *ep, EjsVar *thisObj, const char *xmlString){ XmlState *parser; Exml *xp; xp = initParser(ep, thisObj, "string"); parser = exmlGetParseArg(xp); parser->inputBuf = xmlString; parser->inputSize = strlen(xmlString); exmlSetInputStream(xp, readStringData, (void*) 0); if (exmlParse(xp) < 0) { if (! ejsGotException(ep)) { ejsError(ep, EJS_IO_ERROR, "Can't parse XML string\nError %s", exmlGetErrorMsg(xp)); } termParser(xp); return -1; } ejsSetReturnValue(ep, parser->nodeStack[0].obj); termParser(xp); return 0;}/******************************************************************************/static int text(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv){ EjsVar *vp; vp = ejsGetVarPtr(ejsGetSimpleProperty(ep, thisObj, E4X_TEXT_PROPERTY)); if (vp == 0) { ejsSetReturnValueToString(ep, ""); return 0; } ejsSetReturnValue(ep, vp); return 0;}/******************************************************************************//* * Return the tag name */static int name(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv){ EjsVar *vp; vp = ejsGetVarPtr(ejsGetSimpleProperty(ep, thisObj, E4X_TAG_NAME_PROPERTY)); if (vp == 0) { ejsSetReturnValueToString(ep, ""); return 0; } ejsSetReturnValue(ep, vp);#if UNDEFINED char *name; /* MOB -- not ideal as we can't guarantee thisObj is a property */ name = ejsGetPropertyPtr(thisObj)->name; if (name == 0) { name = ""; } ejsSetReturnValueToString(ep, name); #endif return 0;}/******************************************************************************//* MOB -- temporary only */static int setText(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv){ if (argc != 1) { ejsArgError(ep, "usage: setText(string)"); } ejsSetProperty(ep, thisObj, E4X_TEXT_PROPERTY, argv[0]); ejsSetReturnValue(ep, argv[0]); return 0;}/******************************************************************************/static Exml *initParser(Ejs *ep, EjsVar *thisObj, const char *fileName){ XmlState *parser; Exml *xp; xp = exmlOpen(ep, 512, E4X_BUF_MAX); mprAssert(xp); /* * Create the parser stack */ parser = mprAllocTypeZeroed(ep, XmlState); parser->ep = ep; parser->nodeStack[0].obj = thisObj; parser->xmlClass = ejsGetClass(ep, 0, "XML"); parser->xmlListClass = ejsGetClass(ep, 0, "XMLList"); parser->fileName = fileName; exmlSetParseArg(xp, parser); exmlSetParserHandler(xp, parserHandler); return xp;}/******************************************************************************/static void termParser(Exml *xp){ mprFree(exmlGetParseArg(xp)); exmlClose(xp);}/******************************************************************************//* * XML parsing callback. Called for each elt and attribute/value pair. * For speed, we handcraft the object model here rather than calling * putXmlProperty. * * "<!-- txt -->" parseHandler(efd, , EXML_COMMENT); * "<elt" parseHandler(efd, , EXML_NEW_ELT); * "...att=value" parseHandler(efd, , EXML_NEW_ATT); * "<elt ...>" parseHandler(efd, , EXML_ELT_DEFINED); * "<elt/>" parseHandler(efd, , EXML_SOLO_ELT_DEFINED); * "<elt> ...<" parseHandler(efd, , EXML_ELT_DATA); * "...</elt>" parseHandler(efd, , EXML_END_ELT); * * Note: we recurse on every new nested elt. */static int parserHandler(Exml *xp, int state, const char *tagName, const char *attName, const char *value){ XmlState *parser; XmlTagState *tos; EjsVar *currentNode, *vp, *tagNode, *parent, *vpx; EjsProperty *pp; Ejs *ep; char *name; parser = (XmlState*) xp->parseArg; ep = parser->ep; tos = &parser->nodeStack[parser->topOfStack]; currentNode = tos->obj; mprAssert(state >= 0); mprAssert(tagName && *tagName); switch (state) { case EXML_PI: /* * By using a property name with a leading space, we can store * non-user-visible processing instructions as regular properties. */ pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode, E4X_PI_PROPERTY); ejsMakePropertyEnumerable(pp, 1); vp = ejsGetVarPtr(pp); ejsWriteVarAsString(ep, vp, value); ejsSetVarFlags(vp, EJS_XML_FLAGS_PI); break; case EXML_COMMENT: /* * By using a property name with a leading space, we can store * non- user-visible comments as regular properties. */ pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode, E4X_COMMENT_PROPERTY); ejsMakePropertyEnumerable(pp, 1); vp = ejsGetVarPtr(pp); ejsWriteVarAsString(ep, vp, value); ejsSetVarFlags(vp, EJS_XML_FLAGS_COMMENT); break; case EXML_NEW_ELT: if (parser->topOfStack > E4X_MAX_NODE_DEPTH) { ejsError(ep, EJS_IO_ERROR, "XML nodes nested too deeply in %s at line %d", parser->fileName, exmlGetLineNumber(xp)); return MPR_ERR_BAD_SYNTAX; } name = mprStrdup(xp, tagName); if (name == 0) { return MPR_ERR_MEMORY; } if (cleanTagName(name) < 0) { ejsError(ep, EJS_TYPE_ERROR, "Bad XML tag name in %s at %d", parser->fileName, exmlGetLineNumber(xp)); mprFree(name); return MPR_ERR_BAD_SYNTAX; } pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode, name); ejsMakePropertyEnumerable(pp, 1); tagNode = ejsGetVarPtr(pp); /* MOB -- OPT */ vpx = ejsCreateXml(ep); vp = ejsWriteVar(ep, tagNode, vpx, EJS_SHALLOW_COPY); ejsMakeObjLive(vp, 1); ejsFreeVar(ep, vpx); /* MOB -- return code */ pp = ejsSetPropertyToString(ep, vp, E4X_TAG_NAME_PROPERTY, name); ejsMakePropertyEnumerable(pp, 0); ejsSetVarFlags(vp, EJS_XML_FLAGS_ELEMENT); ejsMakePropertyEnumerable(ejsGetPropertyPtr(vp), 1); tos = &parser->nodeStack[++(parser->topOfStack)]; currentNode = tos->obj = vp; tos->attributes = 0; tos->comments = 0; mprFree(name); break; case EXML_NEW_ATT: if (mprAllocSprintf(MPR_LOC_ARGS(xp), &name, 0, "@%s", attName) < 0) { return MPR_ERR_MEMORY; } pp = ejsCreateProperty(ep, currentNode, name); ejsMakePropertyEnumerable(pp, 1); vp = ejsGetVarPtr(pp); ejsWriteVarAsString(ep, vp, value); ejsSetVarFlags(vp, EJS_XML_FLAGS_ATTRIBUTE); mprFree(name); break; case EXML_SOLO_ELT_DEFINED: parser->topOfStack--; mprAssert(parser->topOfStack >= 0); tos = &parser->nodeStack[parser->topOfStack]; break; case EXML_ELT_DEFINED: if (parser->topOfStack > 0) { parent = parser->nodeStack[parser->topOfStack - 1].obj; ejsSetProperty(ep, currentNode, E4X_PARENT_PROPERTY, parent); } break; case EXML_ELT_DATA: case EXML_CDATA: pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode, E4X_TEXT_PROPERTY); ejsMakePropertyEnumerable(pp, 1); vp = ejsGetVarPtr(pp); ejsWriteVarAsString(ep, vp, value); ejsSetVarFlags(vp, EJS_XML_FLAGS_TEXT); break; case EXML_END_ELT: /* * This is the closing element in a pair "<x>...</x>". * Pop the stack frame off the elt stack */ parser->topOfStack--; mprAssert(parser->topOfStack >= 0); tos = &parser->nodeStack[parser->topOfStack]; break; default: ejsError(ep, EJS_IO_ERROR, "XML error in %s at %d\nDetails %s", parser->fileName, exmlGetLineNumber(xp), exmlGetErrorMsg(xp)); mprAssert(0); return MPR_ERR_BAD_SYNTAX; } return 0;}/******************************************************************************/static char *cleanTagName(char *name){ char *cp; for (cp = name; *cp; cp++) { if (*cp == ':') { *cp = '_'; } else if (!isalnum(*cp) && *cp != '_' && *cp != '$' && *cp != '@') { return 0; } } return name;}/******************************************************************************/static int readFileData(Exml *xp, void *data, char *buf, int size){ mprAssert(xp); mprAssert(data); mprAssert(buf); mprAssert(size > 0); return mprRead((MprFile*) data, buf, size);}/******************************************************************************/static int readStringData(Exml *xp, void *data, char *buf, int size){ XmlState *parser; int rc, len; mprAssert(xp); mprAssert(buf); mprAssert(size > 0); parser = (XmlState*) xp->parseArg; if (parser->inputPos < parser->inputSize) { len = min(size, (parser->inputSize - parser->inputPos)); rc = mprMemcpy(buf, size, &parser->inputBuf[parser->inputPos], len); parser->inputPos += len; return rc; } return 0;}/******************************************************************************/static int save(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv){ const char *fileName; MprBuf *buf; MprFile *file;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -