我如何在嵌套的 dom 树中提取特定 dom 属性的列表?

How do i extract a list of specific dom-attributes in a nested dom tree?

我想遍历并收集具有data-table属性的节点,提取其值,然后获取其具有data-field或其他属性的子节点,并提取其将被保存的值作为列表。

从下面的Html示例中,我已经在[=38=中设置了dom-属性的锚点]-tree,意在将它们遍历并抽取后转化为模型结构

    <body>
        <div class="wrap" data-table="page"> Sample Text <p data-field="heading" class="format" >Welcome to this page</p>
            <div class="flex-grid generic-card">
                <h1 class="card " data-field="intro">Text </h1>
               <div class="card " data-field="body"></div>
            </div>
        </div>

我希望最终结果是一个平面列表的形式,其中包含类似于 (page . ("title" "intro" "body"))

的内容

使用以下代码,我能够遍历节点并提取 'data-table',但问题是,我无法提取附加到 data-tabledata-field。 我没有成功地尝试使用递归方法,该方法包括重复 'dom-struct'dom-search 函数的示例。 我注意到 libxml-parse-html-region'' returns 空字符串,在 dom 节点旁边有换行符,在解析 dom 树后会生成错误。

这段代码的目的是递归地从树中提取节点

(require 'dom)
(defun dom-struct (x)
  (print (dom-attr x 'data-table)) ; extract the data-table attribute
  (print (dom-tag (dom-node x)))        ;extract dom-tag
  (print (dom-children (dom-node x))) ; extract dom-children attached to a node but don't know how to extract data-field attribute
  (print (dom-search (dom-children (dom-node x)) (lambda (node) (assq 'data-attribute (cadr node)))))
  (mapconcat #'dom-struct (dom-children (dom-node x)) ""))

(defun macro-structify (tag-entries)
  (with-temp-buffer
    (insert tag-entries)
    (let* ((mytags (libxml-parse-html-region (point-min) (point-max))))
      (dom-struct (car (dom-by-tag mytags 'body))))))

(let ((myskel "<html>
    <head>
        <title>Demo: Gradient Slide</title>
    </head>
    <link href=\"https://fonts.googleapis.com/css?family=Nunito+Sans\" rel=\"stylesheet\">
    <link rel=\"stylesheet\" href=\"dist/build.css\">
    <body data-table=\"layout\">
        <header data-field=\"title\">
            <h1>Skeleton Screen</h1>
        </header>
        <div class=\"wrap\" data-table=\"page\"> Sample Text <p data-field=\"heading\" class=\"format\" data-attribute=\"somethingsomething\">Welcome to this page</p>
            <div class=\"flex-grid generic-card\">
                <div class=\"card loading\" data-field=\"intro\">Text </div>
               <div class=\"card loading\" data-field=\"body\"></div>
            </div>
        </div>
    </body>
</html>"))
  (macro-structify myskel))

这是一个使用 esxml 包中的 esxml-query 的解决方案。它查找具有 data-field 属性的所有节点,这些节点是具有 data-table 属性的 div 节点的子节点,然后将它们的属性值收集到一个列表中。

(require 'dom)
(require 'esxml-query)

(let* ((myskel "<html>
    <head>
        <title>Demo: Gradient Slide</title>
    </head>
    <link href=\"https://fonts.googleapis.com/css?family=Nunito+Sans\" rel=\"stylesheet\">
    <link rel=\"stylesheet\" href=\"dist/build.css\">
    <body data-table=\"layout\">
        <header data-field=\"title\">
            <h1>Skeleton Screen</h1>
        </header>
        <div class=\"wrap\" data-table=\"page\"> Sample Text <p data-field=\"heading\" class=\"format\" data-attribute=\"somethingsomething\">Welcome to this page</p>
            <div class=\"flex-grid generic-card\">
                <div class=\"card loading\" data-field=\"intro\">Text </div>
               <div class=\"card loading\" data-field=\"body\"></div>
            </div>
        </div>
    </body>
</html>")
       (dom (with-temp-buffer
              (insert myskel)
              (libxml-parse-html-region (point-min) (point-max))))
       (table-node (esxml-query "div[data-table]" dom))
       (model-nodes (esxml-query-all "[data-field]" table-node))
       (model-data-table (dom-attr table-node 'data-table))
       (model-data-fields (mapcar (lambda (node) (dom-attr node 'data-field)) model-nodes)))
  (cons model-data-table model-data-fields))
  ;; => ("page" "heading" "intro" "body")

由于以下几个原因,结果与您指定的不同:

  • 整个 HTML 片段包含一个带有 data-table 属性的 body 标签,然后是一个带有 data-table 属性的 div 标签,但是您的 HTML 片段查看后者,所以我更改了代码以查找具有 data-table 属性
  • div 标记
  • 有一个 header 标签,其 data-field 属性设置为“title”(预期字段),但它是 body 标签的一部分,带有 data-table 属性设置为“布局”,而不是 data-table 属性设置为“页面”(实际字段)的 div 标签
  • 其余字段符合预期,但打印与指定的不同,因为在许多 Lisp 语言中,(foo . (bar baz))(foo bar baz) 相同,通常以后一种形式打印