OSDN Git Service

* Added CSS Parser.
authorkonn <konn@1a406e8e-add9-4483-a2c8-d8cac5b7c224>
Wed, 11 Jun 2008 01:06:38 +0000 (01:06 +0000)
committerkonn <konn@1a406e8e-add9-4483-a2c8-d8cac5b7c224>
Wed, 11 Jun 2008 01:06:38 +0000 (01:06 +0000)
  * Added Child Selector part and Descendant selector part.

git-svn-id: svn+ssh://svn.sourceforge.jp/svnroot/modchxj/mod_chxj/branches/sandbox@2704 1a406e8e-add9-4483-a2c8-d8cac5b7c224

include/chxj_apache.h
include/chxj_css.h
include/chxj_str_util.h
src/chxj_apache.c
src/chxj_css.c
src/chxj_str_util.c
test/chxj_css/Makefile
test/chxj_css/test_chxj_css.c

index 4830b5c..fff2ab0 100644 (file)
@@ -46,6 +46,7 @@
 #  endif
 #  define AP_MODULE_DECLARE_DATA
 #  define APLOG_MARK   __FILE__,__LINE__
+#  undef ap_regex_t
 typedef struct module_struct module;
 struct module_struct {
     int version;
@@ -76,6 +77,17 @@ typedef struct test_request_rec {
   char *unparsed_uri;
   apr_uri_t parsed_uri;
 } request_rec;
+#include "pcre.h"
+typedef struct {
+    void *re_pcre;
+    apr_size_t re_nsub;
+    apr_size_t re_erroffset;
+} ap_regex_t;
+#undef ap_regmatch_t
+typedef struct {
+    int rm_so;
+    int rm_eo;
+} ap_regmatch_t;
 
 
 extern void test_log_error(const char *file, int line, int level, apr_status_t status, const request_rec *r, const char *fmt, ...);
@@ -117,6 +129,11 @@ extern char * chxj_os_escape_path(apr_pool_t *p, const char *path, int partial);
 extern void chxj_set_content_type(request_rec *r, const char *ct);
 extern void * chxj_get_module_config(const ap_conf_vector_t *cv, const module *m);
 extern char *chxj_ap_escape_html(apr_pool_t *p, const char *s);
+extern ap_regex_t *chxj_ap_pregcomp(apr_pool_t *p, const char *pattern, int cflags);
+extern void chxj_ap_pregfree(apr_pool_t *p, ap_regex_t *reg);
+extern int chxj_ap_regexec(const ap_regex_t *preg, const char *string, apr_size_t nmatch, ap_regmatch_t *pmatch, int eflags);
+extern int chxj_ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags);
+extern char *chxj_ap_pregsub(apr_pool_t *p, const char *input, const char *source, size_t nmatch, ap_regmatch_t pmatch[]);
 
 
 #endif
index 3dc4b9b..26a40b7 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef __CHXJ_CSS_H__
 #define __CHXJ_CSS_H__
 
+#include "mod_chxj.h"
 #include <libcroco/libcroco.h>
 
 
@@ -74,7 +75,7 @@ typedef struct __css_current_stylesheet_stack_t {
 #include "chxj_apache.h"
 extern css_stylesheet_t *chxj_css_parse_from_uri(request_rec *r, apr_pool_t *pool, css_stylesheet_t *old_stylesheet, const char *uri);
 extern void chxj_css_stylesheet_dump(css_stylesheet_t *stylesheet);
-extern css_selector_t *chxj_css_find_selector(request_rec *r, apr_pool_t *pool, css_stylesheet_t *stylesheet, const char *tag_name, const char *class_name, const char *id);
+extern css_selector_t *chxj_css_find_selector(Doc *doc, css_stylesheet_t *stylesheet, Node *node);
 #endif
 /*
  * vim:ts=2 et
index 85e5627..d3369df 100644 (file)
 #include <string.h>
 #include <apr_pools.h>
 
-extern int chxj_chk_numeric(
-  const char*          s);
-
-extern int chxj_atoi(
-  const char*          s);
-
+extern int chxj_chk_numeric(const char *s);
+extern int chxj_atoi(const char *s);
 extern int chxj_strcasenrcmp(apr_pool_t *p, const char *s1, const char *s2, int n);
 extern int chxj_starts_with(const char *str, const char *word);
+extern int chxj_strcount(const char *s, const char *str);
 #endif
 /*
  * vim:ts=2 et
index 2dad6de..c167eee 100644 (file)
  * limitations under the License.
  */
 #include "chxj_apache.h"
+#if defined(CHXJ_TEST)
+#include "pcre.h"
+#undef ap_regex_t
+#undef ap_regmatch_t
+#ifndef POSIX_MALLOC_THRESHOLD
+#define POSIX_MALLOC_THRESHOLD (10)
+#endif
+#endif
 
 const char *
 chxj_apache_run_http_scheme(request_rec *r)
@@ -71,6 +79,178 @@ chxj_ap_escape_html(apr_pool_t *p, const char *s)
   return ap_escape_html(p, s);
 #endif
 }
+
+
+int
+chxj_ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags)
+{
+#if defined(CHXJ_TEST)
+  const char *errorptr;
+  int erroffset;
+  int options = 0;
+  
+  if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS;
+  if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE;
+  
+  preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL);
+  preg->re_erroffset = erroffset;
+  
+  if (preg->re_pcre == NULL) return AP_REG_INVARG;
+  
+  preg->re_nsub = pcre_info((const pcre *)preg->re_pcre, NULL, NULL);
+  return 0;
+#else
+  return ap_regcomp(preg,pattern,cflags);
+#endif
+}
+
+ap_regex_t *
+chxj_ap_pregcomp(apr_pool_t *p, const char *pattern, int cflags)
+{
+#if defined(CHXJ_TEST)
+  ap_regex_t *preg = apr_palloc(p, sizeof(*preg));
+  if (chxj_ap_regcomp(preg, pattern, cflags)) {
+    return NULL;
+  }
+  return preg;
+#else
+  return ap_pregcomp(p, pattern, cflags);
+#endif
+}
+void 
+chxj_ap_pregfree(apr_pool_t *p, ap_regex_t *reg)
+{
+#if defined(CHXJ_TEST)
+#else
+  return ap_pregfree(p, reg);
+#endif
+}
+
+int
+chxj_ap_regexec(const ap_regex_t *preg, const char *string, apr_size_t nmatch, ap_regmatch_t *pmatch, int eflags)
+{
+#if defined(CHXJ_TEST)
+  /* copy from apache2.2.8 server/util_pcre.c */
+  int rc;
+  int options = 0;
+  int *ovector = NULL;
+  int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
+  int allocated_ovector = 0;
+
+  if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE_NOTBOL;
+  if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE_NOTEOL;
+
+  ((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1);  /* Only has meaning after compile */
+
+  if (nmatch > 0) {
+    if (nmatch <= POSIX_MALLOC_THRESHOLD) {
+      ovector = &(small_ovector[0]);
+    }
+    else {
+      ovector = (int *)malloc(sizeof(int) * nmatch * 3);
+      if (ovector == NULL) return AP_REG_ESPACE;
+      allocated_ovector = 1;
+    }
+  }
+
+  rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string), 0, options, ovector, nmatch * 3);
+  if (rc == 0) rc = nmatch;    /* All captured slots were filled in */
+  if (rc >= 0) {
+    apr_size_t i;
+    for (i = 0; i < (apr_size_t)rc; i++) {
+      pmatch[i].rm_so = ovector[i*2];
+      pmatch[i].rm_eo = ovector[i*2+1];
+    }
+    if (allocated_ovector) free(ovector);
+    for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+    return 0;
+  } 
+  else {
+    if (allocated_ovector) free(ovector);
+    switch(rc) {
+    case PCRE_ERROR_NOMATCH: return AP_REG_NOMATCH;
+    case PCRE_ERROR_NULL: return AP_REG_INVARG;
+    case PCRE_ERROR_BADOPTION: return AP_REG_INVARG;
+    case PCRE_ERROR_BADMAGIC: return AP_REG_INVARG;
+    case PCRE_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT;
+    case PCRE_ERROR_NOMEMORY: return AP_REG_ESPACE;
+#ifdef PCRE_ERROR_MATCHLIMIT
+    case PCRE_ERROR_MATCHLIMIT: return AP_REG_ESPACE;
+#endif
+#ifdef PCRE_ERROR_BADUTF8
+    case PCRE_ERROR_BADUTF8: return AP_REG_INVARG;
+#endif
+#ifdef PCRE_ERROR_BADUTF8_OFFSET
+    case PCRE_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG;
+#endif
+    default: return AP_REG_ASSERT;
+    }
+  }
+#else
+  return ap_regexec(preg, string, nmatch, pmatch, eflags);
+#endif
+}
+
+char *
+chxj_ap_pregsub(apr_pool_t *p, const char *input, const char *source, size_t nmatch, ap_regmatch_t pmatch[])
+{
+#if defined(CHXJ_TEST)
+  /* copy from apache2.2.8 server/util.c */
+  const char *src = input;
+  char *dest, *dst;
+  char c;
+  size_t no;
+  int len;
+
+  if (!source) return NULL;
+  if (!nmatch) return apr_pstrdup(p, src);
+
+  len = 0;
+  while ((c = *src++) != '\0') {
+    if (c == '&') no = 0;
+    else if (c == '$' && apr_isdigit(*src))
+      no = *src++ - '0';
+    else
+      no = 10;
+
+    if (no > 9) {                /* Ordinary character. */
+      if (c == '\\' && (*src == '$' || *src == '&'))
+        c = *src++;
+      len++;
+    }
+    else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
+      len += pmatch[no].rm_eo - pmatch[no].rm_so;
+    }
+  }
+  dest = dst = apr_pcalloc(p, len + 1);
+  /* Now actually fill in the string */
+  src = input;
+  while ((c = *src++) != '\0') {
+    if (c == '&')
+      no = 0;
+    else if (c == '$' && apr_isdigit(*src))
+      no = *src++ - '0';
+    else
+      no = 10;
+
+    if (no > 9) {                /* Ordinary character. */
+      if (c == '\\' && (*src == '$' || *src == '&'))
+         c = *src++;
+      *dst++ = c;
+    }
+    else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
+      len = pmatch[no].rm_eo - pmatch[no].rm_so;
+      memcpy(dst, source + pmatch[no].rm_so, len);
+      dst += len;
+    }
+  }
+  *dst = '\0';
+
+  return dest;
+#else
+  return ap_pregsub(p, input, source, nmatch, pmatch);
+#endif
+}
 /*
  * vim:ts=2 et
  */
index 86b6d01..19f9ea7 100644 (file)
 
 #include <libgen.h>
 
+#if defined(CHXJ_TEST)
+#undef ap_regex_t
+#undef ap_regmatch_t
+#endif
+
 #undef list_insert
 #undef list_remove
 #define list_insert(node, point) do {           \
@@ -77,6 +82,9 @@ static css_stylesheet_t *s_chxj_css_parse_from_uri(request_rec *r, apr_pool_t *p
 static int s_is_already_imported(struct css_already_import_stack *imported_stack_head, const char *url);
 static css_stylesheet_t *s_merge_stylesheet(apr_pool_t *pool, css_stylesheet_t *old_stylesheet, css_stylesheet_t *new_stylesheet);
 static void s_copy_already_import_stack(apr_pool_t *pool, struct css_already_import_stack *base, struct css_already_import_stack *imported_stack);
+static css_selector_t *s_search_selector_regexp(Doc *doc, request_rec *r, apr_pool_t *pool, css_stylesheet_t *stylesheet, const char *pattern_str1, const char *pattern_str2, Node *node);
+static void s_get_tag_and_class_and_id(Doc *doc, Node *node, char **tag_name, char **class_name, char **id);
+static char *s_cmp_now_node_vs_current_style(Doc *doc, request_rec *r, apr_pool_t *pool, char *src, ap_regex_t *pattern4, Node *node);
 
 /**
  * Data is acquired from url specified by using libserf. 
@@ -97,24 +105,111 @@ chxj_css_parse_from_uri(request_rec *r, apr_pool_t *pool, css_stylesheet_t *old_
 
 /**
  * find selector engine.
- * @param r request_rec
- * @param pool pool
+ * @param doc        Doc structure.
  * @param stylesheet Retrieval object.
- * @param tag_name tag name.
- * @param class_name class name.
- * @param id id.
+ * @param node       this node.
  * @return css_selector_t if any. null if not found.
  *
  */
 css_selector_t *
-chxj_css_find_selector(request_rec *r, apr_pool_t *pool, css_stylesheet_t *stylesheet, const char *tag_name, const char *class_name, const char *id)
+chxj_css_find_selector(Doc *doc, css_stylesheet_t *stylesheet, Node *node)
 {
+  request_rec *r    = doc->r;
+  apr_pool_t  *pool = doc->pool;
   css_selector_t *sel = NULL;
   css_selector_t *cur = NULL;
+  css_selector_t *tail = NULL;
+  char *tag_name   = NULL;
+  char *class_name = NULL;
+  char *id         = NULL;
+  Attr *attr;
   DBG(r, "start chxj_css_find_selector()");
-  for (cur = stylesheet->selector_head.next; cur != &stylesheet->selector_head; cur = cur->next) {
-    DBG(r, "cur->name:[%s]", cur->name);
+
+  s_get_tag_and_class_and_id(doc, node, &tag_name, &class_name, &id);
+  
+  if (! tag_name || strcasecmp("ROOT", tag_name) == 0) {
+    ERR(r, "%s:%d tag_name is null", APLOG_MARK);
+    return NULL;
+  }
+  char *pattern_str1 = NULL;
+  char *pattern_str2 = NULL;
+  if (class_name && id) {
+    pattern_str1 = apr_psprintf(pool, 
+                                "^((%s|\\*)(\\.%s)?(#%s)?|(\\*|)\\.%s(#%s)?|(\\*|)(\\.%s)?#%s)$",
+                                tag_name,
+                                class_name,
+                                id,
+                                class_name,
+                                id,
+                                class_name,
+                                id);
+    pattern_str2 = apr_psprintf(pool,
+                                ".*([ >+])((%s|\\*)(\\.%s)?(#%s)?|(\\*|)\\.%s(#%s)?|(\\*|)(\\.%s)?#%s)$",
+                                tag_name,
+                                class_name,
+                                id,
+                                class_name,
+                                id,
+                                class_name,
+                                id);
+    sel = s_search_selector_regexp(doc, r, pool, stylesheet, pattern_str1, pattern_str2, node);
+    if (sel) {
+      DBG(r, "end chxj_css_find_selector()");
+      return sel;
+    }
+  }
+  else if (id) {
+    pattern_str1 = apr_psprintf(pool, 
+                                "^((%s|\\*)(#%s)?|(\\*|)(#%s)?|(\\*|)#%s)$",
+                                tag_name,
+                                id,
+                                id,
+                                id);
+    pattern_str2 = apr_psprintf(pool,
+                                ".*([ >+])((%s|\\*)(#%s)?|(\\*|)(#%s)?|(\\*|)#%s)$",
+                                tag_name,
+                                id,
+                                id,
+                                id);
+    sel = s_search_selector_regexp(doc, r, pool, stylesheet, pattern_str1, pattern_str2, node);
+    if (sel) {
+      DBG(r, "end chxj_css_find_selector()");
+      return sel;
+    }
   }
+  else if (class_name) {
+    pattern_str1 = apr_psprintf(pool, 
+                                "^((%s|\\*)(\\.%s)?|(\\*|)\\.%s|(\\*|)(\\.%s))$",
+                                tag_name,
+                                class_name,
+                                class_name,
+                                class_name);
+    pattern_str2 = apr_psprintf(pool,
+                                ".*([ >+])((%s|\\*)(\\.%s)?|(\\*|)\\.%s|(\\*|)(\\.%s)?)$",
+                                tag_name,
+                                class_name,
+                                class_name,
+                                class_name);
+    sel = s_search_selector_regexp(doc, r, pool, stylesheet, pattern_str1, pattern_str2, node);
+    if (sel) {
+      DBG(r, "end chxj_css_find_selector()");
+      return sel;
+    }
+  }
+  else {
+    pattern_str1 = apr_psprintf(pool, 
+                                "^(%s|\\*)$",
+                                tag_name);
+    pattern_str2 = apr_psprintf(pool,
+                                ".*([ >+])(%s|\\*)$",
+                                tag_name);
+    sel = s_search_selector_regexp(doc, r, pool, stylesheet, pattern_str1, pattern_str2, node);
+    if (sel) {
+      DBG(r, "end chxj_css_find_selector()");
+      return sel;
+    }
+  }
+
   DBG(r, "end chxj_css_find_selector()");
   return sel;
 }
@@ -124,6 +219,108 @@ chxj_css_find_selector(request_rec *r, apr_pool_t *pool, css_stylesheet_t *style
 /* STATIC                                                                    */
 /*                                                                           */
 /*===========================================================================*/
+static css_selector_t *
+s_search_selector_regexp(Doc *doc, request_rec *r, apr_pool_t *pool, css_stylesheet_t *stylesheet, const char *pattern_str1, const char *pattern_str2, Node *node)
+{
+  Node *node_sv = node;
+  css_selector_t *tail;
+  css_selector_t *cur;
+  DBG(r, "pattern1:[%s]", pattern_str1);
+  DBG(r, "pattern2:[%s]", pattern_str2);
+  ap_regex_t *pattern1 = chxj_ap_pregcomp(pool, pattern_str1, AP_REG_EXTENDED|AP_REG_ICASE);
+  ap_regex_t *pattern2 = chxj_ap_pregcomp(pool, pattern_str2, AP_REG_EXTENDED|AP_REG_ICASE);
+  ap_regex_t *pattern3 = chxj_ap_pregcomp(pool, "^.*([>+ ])([^>+ ]+?)$", AP_REG_EXTENDED|AP_REG_ICASE);
+  ap_regex_t *pattern4 = chxj_ap_pregcomp(pool, "^([^.#]+?)(\\.[^#]+?)?(#.+?)?$", AP_REG_EXTENDED|AP_REG_ICASE);
+                              
+  tail = (css_selector_t *)((apr_size_t)stylesheet->selector_head.ref - (apr_size_t)APR_OFFSETOF(css_selector_t, next));
+  for (cur = tail; 
+       cur != &stylesheet->selector_head; 
+       cur = (css_selector_t *)((apr_size_t)cur->ref - (apr_size_t)APR_OFFSETOF(css_selector_t, next))) {
+    ap_regmatch_t match[256];
+    DBG(r, "cur->name:[%s]", cur->name);
+    if (chxj_ap_regexec(pattern1, cur->name, pattern1->re_nsub + 1, match, 0) == 0) {
+      DBG(r, "match(independent of)");
+      return cur;
+    }
+    else 
+    if (chxj_ap_regexec(pattern2, cur->name, pattern2->re_nsub + 1, match, 0) == 0) {
+      DBG(r, "match(depend on) [%s]", cur->name);
+      char *src = apr_pstrdup(pool, cur->name);
+      char *one = chxj_ap_pregsub(pool, "$1",src, pattern2->re_nsub + 1, match);
+      int loop = 0;
+      do {
+        DBG(r, "start do while");
+        node = node->parent;
+        *strrchr(src, *one) = 0;
+        switch (*one) {
+        case '>': /* Child selectors */
+          DBG(r, "child selectors");
+          if (chxj_ap_regexec(pattern3, src, pattern3->re_nsub + 1, match, 0) == 0) {
+            DBG(r, "has any parent");
+            one = chxj_ap_pregsub(pool, "$1",src, pattern3->re_nsub + 1, match);
+            char *ret = s_cmp_now_node_vs_current_style(doc, r, pool, strrchr(src, *one)+1, pattern4, node);
+            if (ret) {
+              DBG(r, "continue do while");
+              loop = 1;
+            }
+          }
+          else {
+            DBG(r, "parent:[%x]", node);
+            DBG(r, "parent->name:[%s] src:[%s]", node->name, src);
+            char *ret = s_cmp_now_node_vs_current_style(doc, r, pool, src, pattern4, node);
+            if (ret) return ret;
+            loop = 0;
+          }
+          break;
+        case '+': /* Adjacent sibling selectors */
+          loop = 0;
+          break;
+        case ' ': /* Descendant selectors */
+          DBG(r, "descendant selectors");
+          if (chxj_ap_regexec(pattern3, src, pattern3->re_nsub + 1, match, 0) == 0) {
+            DBG(r, "has any parent");
+            one = chxj_ap_pregsub(pool, "$1",src, pattern3->re_nsub + 1, match);
+            for (; node; node = node->parent) {
+              if (strcasecmp(node->name, "ROOT") == 0) {
+                DBG(r, "unmatch");
+                loop = 0;
+                break;
+              }
+              char *ret = s_cmp_now_node_vs_current_style(doc, r, pool, strrchr(src, *one)+1, pattern4, node);
+              if (ret) {
+                DBG(r, "continue do while");
+                loop = 1;
+                break;
+              }
+            }
+          }
+          else {
+            DBG(r, "parent:[%x]", node);
+            DBG(r, "parent->name:[%s] src:[%s]", node->name, src);
+            for (; node; node = node->parent) {
+              if (strcasecmp(node->name, "ROOT") == 0) {
+                DBG(r, "unmatch");
+                loop = 0;
+                break;
+              }
+              char *ret = s_cmp_now_node_vs_current_style(doc, r, pool, src, pattern4, node);
+              if (ret) return ret;
+            }
+          }
+          break;
+        default:
+          loop = 0;
+          DBG(r, "unmatch(unknown separator)");
+        }
+      } while(loop);
+      node = node_sv;
+    }
+    DBG(r, "unmatch [%s]", cur->name);
+  }
+  chxj_ap_pregfree(pool, pattern1);
+  chxj_ap_pregfree(pool, pattern2);
+  return NULL;
+}
 static css_stylesheet_t *
 s_chxj_css_parse_from_uri(request_rec *r, apr_pool_t *pool, struct css_already_import_stack *imported_stack, css_stylesheet_t *old_stylesheet, const char *uri)
 {
@@ -634,6 +831,67 @@ chxj_css_stylesheet_dump(css_stylesheet_t *stylesheet)
   }
 }
 
+static void
+s_get_tag_and_class_and_id(Doc *doc, Node *node, char **tag_name, char **class_name, char **id)
+{
+  Attr *attr;
+  *tag_name = node->name;
+  for (attr = qs_get_attr(doc, node); attr; attr = qs_get_next_attr(doc,attr)) {
+    char *name  = qs_get_attr_name(doc,attr);
+    char *value = qs_get_attr_value(doc,attr);
+    if (STRCASEEQ('c','C', "class", name)) {
+      if (*value != 0) {
+        *class_name = value;
+      }
+    }
+    else 
+    if (STRCASEEQ('i','I', "id", name)) {
+      if (*value != 0) {
+        *id = value;
+      }
+    }
+    if (*id && *class_name) break;
+  }
+}
+
+static char *
+s_cmp_now_node_vs_current_style(Doc *doc, request_rec *r, apr_pool_t *pool, char *src, ap_regex_t *pattern4, Node *node)
+{
+  ap_regmatch_t match[256];
+  if (chxj_ap_regexec(pattern4, src, pattern4->re_nsub + 1, match, 0) == 0) {
+    char *tag_name   = chxj_ap_pregsub(pool, "$1", src, pattern4->re_nsub + 1, match);
+    char *class_name = chxj_ap_pregsub(pool, "$2", src, pattern4->re_nsub + 1, match);
+    char *id_name    = chxj_ap_pregsub(pool, "$3", src, pattern4->re_nsub + 1, match);
+    DBG(r, "tag:[%s] class:[%s] id:[%s]", tag_name, class_name, id_name);
+    if (!node) {
+      DBG(r, "unmatch(parent is null)");
+      return NULL;
+    }
+    char *node_tag_name   = NULL;
+    char *node_class_name = NULL;
+    char *node_id_name    = NULL;
+    s_get_tag_and_class_and_id(doc, node, &node_tag_name, &node_class_name, &node_id_name);
+    if (strcasecmp(node_tag_name, tag_name) == 0 || strcmp("*", tag_name) == 0) {
+      if (class_name && *class_name != 0) {
+        if (strcasecmp(node_class_name, &class_name[1]) != 0) {
+          DBG(r, "unmatch (class) node:[%s] style:[%s]", node_class_name, &class_name[1]);
+          return NULL;
+        }
+      }
+      if (id_name && *id_name != 0) {
+        if (strcasecmp(node_id_name, &id_name[1]) != 0) {
+          DBG(r, "unmatch (id)");
+          return NULL;
+        }
+      }
+      DBG(r, "match");
+      return src;
+    }
+    DBG(r, "unmatch(tag) tag:[%s] vs [%s]", tag_name, node_tag_name);
+  }
+  return NULL;
+}
+
 #if 0
 css_stylesheet_t *
 chxj_css_parse_from_style_tag(apr_pool_t *pool, css_stylesheet_t *old_stylesheet, const char *style_value)
index 6e56605..e26c906 100644 (file)
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 #include "chxj_str_util.h"
+#if !defined (__CHXJ_STR_UTIL_C__)
+#define __CHXJ_STR_UTIL_C__
 
 int
 chxj_chk_numeric(const char *s)
@@ -159,6 +161,27 @@ chxj_starts_with(const char *str, const char *word)
   if (len == 0) len = 1;
   return strncasecmp(s, w, len) == 0;
 }
+
+
+int
+chxj_strcount(const char *s, const char *str)
+{
+  register char *p = (char *)s;
+  register char i;
+  int len = strlen(str);
+  int count = 0;
+  while (*p) {
+    for (i=0; i<len; i++) {
+      if (*p == (char)str[i]) {
+        count++;
+        break;
+      }
+    }
+    p++;
+  }
+  return count;
+}
+#endif
 /*
  * vim:ts=2 et
  */
index 175bb86..11bee54 100644 (file)
@@ -20,7 +20,7 @@ test: $(TARGET)
        ./$(TARGET)
 
 $(TARGET): $(TARGET).c
-       gcc -g -o $@ -Wall -lcunit $< $(INC_DIR) -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE  -lapr-1 -laprutil-1 `croco-0.6-config --cflags`  `croco-0.6-config --libs` $(TOP_DIR)/src/serf/.libs/libserf-0.a
+       gcc -g -o $@ -Wall -lcunit $< $(INC_DIR) -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE  -lapr-1 -laprutil-1 `croco-0.6-config --cflags`  `croco-0.6-config --libs` $(TOP_DIR)/src/serf/.libs/libserf-0.a -lpcre
 
 clean:
        rm -f ./$(TARGET)
index c6c30d5..30fc08c 100644 (file)
 #include "chxj_url_encode.c"
 #include "chxj_apache.c"
 #include "chxj_str_util.c"
+#include "qs_malloc.c"
+#include "qs_parse_string.c"
+#include "qs_log.c"
+#include "qs_parse_tag.c"
+#include "qs_parse_attr.c"
+#include "qs_ignore_sp.c"
 
 
 
@@ -29,7 +35,35 @@ void test_chxj_css_parse_from_uri_005();
 void test_chxj_css_parse_from_uri_006();
 void test_chxj_css_parse_from_uri_007();
 void test_chxj_css_parse_from_uri_008();
-void test_chxj_css_parse_from_uri_009();
+
+/* chxj_css_find_selector */
+void test_chxj_css_find_selector_001();
+void test_chxj_css_find_selector_002();
+void test_chxj_css_find_selector_003();
+void test_chxj_css_find_selector_004();
+void test_chxj_css_find_selector_005();
+void test_chxj_css_find_selector_006();
+void test_chxj_css_find_selector_007();
+void test_chxj_css_find_selector_unmatch_pattern_001();
+void test_chxj_css_find_selector_unmatch_pattern_002();
+void test_chxj_css_find_selector_unmatch_pattern_003();
+/* E > F */
+void test_chxj_css_find_selector_p_001();
+void test_chxj_css_find_selector_p_002();
+void test_chxj_css_find_selector_p_003();
+void test_chxj_css_find_selector_p_004();
+void test_chxj_css_find_selector_p_005();
+void test_chxj_css_find_selector_p_006();
+void test_chxj_css_find_selector_p_007();
+void test_chxj_css_find_selector_p_008();
+void test_chxj_css_find_selector_p_009();
+
+/* E F */
+void test_chxj_css_find_selector_des_001();
+void test_chxj_css_find_selector_des_002();
+void test_chxj_css_find_selector_des_003();
+void test_chxj_css_find_selector_des_004();
+void test_chxj_css_find_selector_des_005();
 /* pend */
 
 int
@@ -47,7 +81,31 @@ main()
   CU_add_test(css_suite, "test css 006",                                    test_chxj_css_parse_from_uri_006);
   CU_add_test(css_suite, "test css 007",                                    test_chxj_css_parse_from_uri_007);
   CU_add_test(css_suite, "test css 008",                                    test_chxj_css_parse_from_uri_008);
-  CU_add_test(css_suite, "test css 009",                                    test_chxj_css_parse_from_uri_009);
+  CU_add_test(css_suite, "test css find_selector 001",                      test_chxj_css_find_selector_001);
+  CU_add_test(css_suite, "test css find_selector 002",                      test_chxj_css_find_selector_002);
+  CU_add_test(css_suite, "test css find_selector 003",                      test_chxj_css_find_selector_003);
+  CU_add_test(css_suite, "test css find_selector 004",                      test_chxj_css_find_selector_004);
+  CU_add_test(css_suite, "test css find_selector 005",                      test_chxj_css_find_selector_005);
+  CU_add_test(css_suite, "test css find_selector 006",                      test_chxj_css_find_selector_006);
+  CU_add_test(css_suite, "test css find_selector 007",                      test_chxj_css_find_selector_007);
+  CU_add_test(css_suite, "test css find_selector unmatch 001",              test_chxj_css_find_selector_unmatch_pattern_001);
+  CU_add_test(css_suite, "test css find_selector unmatch 002",              test_chxj_css_find_selector_unmatch_pattern_002);
+  CU_add_test(css_suite, "test css find_selector unmatch 003",              test_chxj_css_find_selector_unmatch_pattern_003);
+  CU_add_test(css_suite, "test css find_selector with '>' 001",             test_chxj_css_find_selector_p_001);
+  CU_add_test(css_suite, "test css find_selector with '>' 002",             test_chxj_css_find_selector_p_002);
+  CU_add_test(css_suite, "test css find_selector with '>' 003",             test_chxj_css_find_selector_p_003);
+  CU_add_test(css_suite, "test css find_selector with '>' 004",             test_chxj_css_find_selector_p_004);
+  CU_add_test(css_suite, "test css find_selector with '>' 005",             test_chxj_css_find_selector_p_005);
+  CU_add_test(css_suite, "test css find_selector with '>' 006",             test_chxj_css_find_selector_p_006);
+  CU_add_test(css_suite, "test css find_selector with '>' 007",             test_chxj_css_find_selector_p_007);
+  CU_add_test(css_suite, "test css find_selector with '>' 008",             test_chxj_css_find_selector_p_008);
+  CU_add_test(css_suite, "test css find_selector with '>' 009",             test_chxj_css_find_selector_p_009);
+
+  CU_add_test(css_suite, "test css find_selector with ' ' 001",             test_chxj_css_find_selector_des_001);
+  CU_add_test(css_suite, "test css find_selector with ' ' 002",             test_chxj_css_find_selector_des_002);
+  CU_add_test(css_suite, "test css find_selector with ' ' 003",             test_chxj_css_find_selector_des_003);
+  CU_add_test(css_suite, "test css find_selector with ' ' 004",             test_chxj_css_find_selector_des_004);
+  CU_add_test(css_suite, "test css find_selector with ' ' 005",             test_chxj_css_find_selector_des_005);
   /* aend */
 
   CU_basic_run_tests();
@@ -501,27 +559,1155 @@ void test_chxj_css_parse_from_uri_008()
 }
 
 
-
+/*===========================================================================*/
+/*                                                                           */
+/* chxj_css_find_selector                                                    */
+/*                                                                           */
+/*===========================================================================*/
 char *test_chxj_serf_get009(request_rec *r, apr_pool_t *ppool, const char *uri_path)
 {
-  static char *css = "html { display: none }";
+  static char *css = "html,body, hr.abc#id1 { display: none }";
 
   return css;
 }
-void test_chxj_css_parse_from_uri_009()
+void test_chxj_css_find_selector_001()
 {
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
   css_stylesheet_t *ret;
   css_selector_t *sel;
   APR_INIT;
   chxj_serf_get = test_chxj_serf_get009;
+  fprintf(stderr, "start %s\n", __func__);
+
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+#undef TEST_STRING
+  fprintf(stderr, "end %s\n", __func__);
+}
+
+
+
+char *test_chxj_serf_get010(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, .abc#id1 { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_002()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get010;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+
+
+char *test_chxj_serf_get011(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, #id1 { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_003()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get011;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+
+
+char *test_chxj_serf_get012(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, .abc { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_004()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get012;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+
+char *test_chxj_serf_get013(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, hr.abc { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_005()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get013;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+
+
+char *test_chxj_serf_get014(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, hr#id1 { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_006()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get014;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+
+
+char *test_chxj_serf_get015(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_007()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get015;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+
+char *test_chxj_serf_get016(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, li { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_unmatch_pattern_001()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get016;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel == NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+char *test_chxj_serf_get017(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, hr.def { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_unmatch_pattern_002()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get017;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel == NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get018(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, hr#id2 { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_unmatch_pattern_003()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get018;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel == NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+/*===========================================================================*/
+/* E > F                                                                     */
+/*===========================================================================*/
+char *test_chxj_serf_get019(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, body>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_001()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get019;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get020(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html>body>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_002()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get020;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get021(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html>body>div>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_003()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div><hr class=\"abc\" id=\"id1\"></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get021;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get022(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html>body>div>div>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_004()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div><div><hr class=\"abc\" id=\"id1\"></div></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get022;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get023(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html>body>div.def#id2>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_005()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get023;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get024(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html>body>div.abc#id2>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_006()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get024;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel == NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get025(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, body>*.def#id2>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_007()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get025;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get026(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, body.def#id2>*.def#id2>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_008()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get026;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+char *test_chxj_serf_get027(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, body.abc#id2>*.def#id2>hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_p_009()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><hr class=\"abc\" id=\"id1\"></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get027;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel == NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+char *test_chxj_serf_get028(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, body hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_des_001()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><div><hr class=\"abc\" id=\"id1\"></div></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get028;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+char *test_chxj_serf_get029(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html body hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_des_002()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><div><hr class=\"abc\" id=\"id1\"></div></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get029;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+char *test_chxj_serf_get030(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html body.def#id2 hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_des_003()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><div><hr class=\"abc\" id=\"id1\"></div></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get030;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+char *test_chxj_serf_get031(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html body.abc#id2 hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_des_004()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><div><hr class=\"abc\" id=\"id1\"></div></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get031;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+
+  apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
+
+  ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
+  CU_ASSERT(ret != NULL);
+
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel == NULL);
+  APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
+}
+
+char *test_chxj_serf_get032(request_rec *r, apr_pool_t *ppool, const char *uri_path)
+{
+  static char *css = "html,body, html body.def hr { display: none }";
+
+  return css;
+}
+void test_chxj_css_find_selector_des_005()
+{
+#define TEST_STRING "<html><head></head><body class=\"def\" id=\"id2\"><div class=\"def\" id=\"id2\"><div><hr class=\"abc\" id=\"id1\"></div></div></body></html>"
+  Doc doc;
+  Node *node;
+  Node *tmp_node;
+  Node *node_sv;
+  css_stylesheet_t *ret;
+  css_selector_t *sel;
+  APR_INIT;
+  chxj_serf_get = test_chxj_serf_get032;
+
+  fprintf(stderr, "start %s\n", __func__);
+  doc.r = &r;
+  qs_init_malloc(&doc);
+  qs_init_root_node(&doc);
+  doc.parse_mode = PARSE_MODE_CHTML;
+
+  node_sv = node = qs_parse_string(&doc, TEST_STRING, sizeof(TEST_STRING)-1);
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->next;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
+  tmp_node = node->child;
+  node = tmp_node;
 
   apr_uri_parse(p, "http://localhost:888/abc", &r.parsed_uri); \
 
   ret = chxj_css_parse_from_uri(&r, r.pool, NULL, "/hoge.css");
   CU_ASSERT(ret != NULL);
 
-  sel = chxj_css_find_selector(&r, r.pool, ret, "html", NULL, NULL);
+  sel = chxj_css_find_selector(&doc, ret, node);
+  CU_ASSERT(sel != NULL);
   APR_TERM;
+  fprintf(stderr, "end %s\n", __func__);
+#undef TEST_STRING
 }
 /*
  * vim:ts=2 et