/* $Id: TestXmlsq.c $ */ /* * Last updated: * $Date: 2021-07-18 10:29 $ * $Version: 1.0.0 $ */ /* Some tests using the diXmlsq C/C++ interface. * Please report any bugs to <http://cryptosys.net/contact/> */ /******************************* LICENSE *********************************** * Copyright (C) 2020-21 David Ireland, DI Management Services Pty Limited. * All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net> * The code in this module is licensed under the terms of the MIT license, * unless otherwise marked. * For a copy, see <http://opensource.org/licenses/MIT> **************************************************************************** */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "diXmlsq.h" /* * Requires `xmlsq` to be installed on your system, available from <https://www.cryptosys.net/xmlsq/>. * In particular that `diXmlsq.dll` is in your library path. * You must link to `diXmlsq.lib`. In MSVC++ IDE, use * Project > Properties > Linker > Input > Additional Dependencies and add the full path to `diXmlsq.lib`. * E.g. * Additional Dependencies = $(OutDir)diXmlsq.lib;%(AdditionalDependencies) * Using command-line: * CL TestXmlsq.c /link ..\Release\diXmlsq.lib * * Test files are in `xmlsq-testfiles.zip`. */ #ifdef NDEBUG /* Make sure assertion testing is turned on */ #undef NDEBUG #endif #include <assert.h> /* Print quoted string to stdout */ static void pr_quoted_str(const char *prefix, const char *s, const char * suffix) { if (prefix) printf("%s", prefix); printf("'%s'", s); if (suffix) printf("%s", suffix); } int main(void) { long n, i; const char *xmlfile; const char *query; char sbuf[256]; char qbuf[128]; char *buf; long nchars; n = XMLSQ_Gen_Version(); printf("Version = %05ld\n", n); xmlfile = "bookstore.xml"; printf("FILE: %s\n", xmlfile); query = "/"; printf("Get the root element...\n"); printf("Query: %s\n", query); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); query = "(//title)[2]"; printf("Get text of the 2nd title element...\n"); printf("Query: %s\n", query); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); query = "//title"; printf("Get text of the 1st title element...\n"); printf("Query: %s\n", query); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); query = "//title"; printf("Full Xpath query...\n"); printf("Query: %s\n", query); nchars = XMLSQ_FullQuery(NULL, 0, xmlfile, query, 0); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_FullQuery(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); query = "//title"; printf("Full Xpath query with `raw` option...\n"); printf("Query: %s\n", query); nchars = XMLSQ_FullQuery(NULL, 0, xmlfile, query, XMLSQ_RAW); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_FullQuery(buf, nchars, xmlfile, query, XMLSQ_RAW); printf("%s\n", buf); free(buf); query = "(//title)[3]"; printf("Get text of the 3rd title element (UTF-8-encoded)...\n"); // To show properly in cmd type ``chcp 65001`` before calling. printf("Query: %s\n", query); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); query = "(//title)[3]"; printf("Get text of the 3rd title element (asciified)...\n"); printf("Query: %s\n", query); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, XMLSQ_ASCIIFY); assert(nchars >= 0); buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, XMLSQ_ASCIIFY); printf("%s\n", buf); free(buf); query = "//book/title/@lang"; printf("Get text of `lang` attribute in first title element ...\n"); printf("Query: %s\n", query); // Use fixed-length output buffer (!DANGER!) nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); printf("%s\n", sbuf); query = "//book/title/@lang"; printf("Same query in full-query mode...\n"); printf("Query: %s\n", query); // Use fixed-length output buffer (!DANGER!) nchars = XMLSQ_FullQuery(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); printf("%s\n", sbuf); // USE COUNT TO ITERATE MATCHING ELEMENTS query = "//title"; printf("Use the Count function to query each matching element in turn...\n"); printf("Query: %s\n", query); n = XMLSQ_Count(xmlfile, query, 0); printf("Count: %ld\n", n); for (i = 1; i <= n; i++) { // NB one-based // Compose query sprintf(qbuf, "(//title)[%ld]", i); printf(" Query: %s\n", qbuf); // then use it nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, qbuf, XMLSQ_ASCIIFY); assert(nchars >= 0); printf(" %s\n", sbuf); } // HANDLE ERROR STRINGS printf("\nTEST ERRORS...\n"); // Bad query query = "///badquery"; printf("Query: %s\n", query); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars < 0); if (nchars < 0) { // return -N => error string is of length N nchars = -nchars; // Allocate buffer to receive error message buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); } // Missing file xmlfile = "missing.file"; query = "//a"; printf("FILE: %s\n", xmlfile); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars < 0); if (nchars < 0) { // return -N => error string is of length N nchars = -nchars; // Allocate buffer to receive error message buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); } // Input not valid XML xmlfile = "notxml.txt"; query = "//a"; printf("FILE: %s\n", xmlfile); nchars = XMLSQ_GetText(NULL, 0, xmlfile, query, 0); assert(nchars < 0); if (nchars < 0) { // return -N => error string is of length N nchars = -nchars; // Allocate buffer to receive error message buf = malloc(nchars + 1); nchars = XMLSQ_GetText(buf, nchars, xmlfile, query, 0); printf("%s\n", buf); free(buf); } // TEST EMPTY VALUES printf("\nTESTING FOR EMPTY VALUES...\n"); xmlfile = "<a><b foo=''></b><c>test1</c><e/></a>"; // Pass XML as a string printf("xml=%s\n", xmlfile); query = "/"; printf("Query: %s\n", query); nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); printf("%s\n", sbuf); printf("Get text of element b (empty, so add quote delimiters to see something)...\n"); query = "a/b"; printf("Query: %s\n", query); nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); pr_quoted_str("", sbuf, "\n"); printf("And empty attribute foo=\"\"...\n"); query = "//b/@foo"; printf("Query: %s\n", query); nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); pr_quoted_str("", sbuf, "\n"); printf("And empty element e...\n"); query = "//e"; printf("Query: %s\n", query); nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); pr_quoted_str("", sbuf, "\n"); printf("But we get the same result if the element is missing...\n"); query = "//notthere"; printf("Query: %s\n", query); nchars = XMLSQ_GetText(sbuf, sizeof(sbuf) - 1, xmlfile, query, 0); assert(nchars >= 0); pr_quoted_str("", sbuf, "\n"); printf("To differentiate: use the Count function...\n"); query = "//e"; printf("Query: %s\n", query); n = XMLSQ_Count(xmlfile, query, 0); printf("Count=%ld\n", n); assert(n > 0); query = "//notthere"; printf("Query: %s\n", query); n = XMLSQ_Count(xmlfile, query, 0); printf("Count=%ld\n", n); assert(n == 0); return 0; }