a1b10 / cl-xlsx

📜 Read XLSX files with Common Lisp
23 stars 2 forks source link

don't skip every other sheet in cl-xlsx::sheets #5

Closed slyrus closed 3 years ago

slyrus commented 4 years ago

You (or I) can close this but this seemed like a simpler solution to your fix to #2 .

gwangjinkim commented 4 years ago

Thanks a lot!

It really works. But why? :D I couldn't figure out yet ... In my solution, I use a helper variable consumed to remember whether a tag was read (that is when the :start-element had the name "sheet"

(defun sheets (xlsx)
  "Return sheet informations as list of lists (sheet-name sheet-number sheet-address)."
  (klacks:with-open-source (src (source-entry "xl/workbook.xml" xlsx))
    (loop :for key = (klacks:peek src)
      :for consumed = nil
          :while key
          :nconcing (case key
              (:start-element
               (let ((tag-name (klacks:current-qname src)))
             (cond ((equal tag-name "sheet")
                (setf consumed t)
                (list (let* ((sax (klacks:serialize-element src (cxml-xmls:make-xmls-builder)))
                         (attributes (cadr sax)))
                    (list (cadr (assoc "name" attributes :test #'equal))
                          (parse-integer (cadr (assoc "sheetId" attributes :test #'equal)))
                          (concatenate 'string "xl/worksheets/sheet"
                               (cadr (assoc "sheetId" attributes :test #'equal))
                               ".xml")))))
                   (t nil))))
              (otherwise nil))
      :do (unless consumed
        (klacks:consume src)))))

In case it was consumed, the klacks:serialize-element already consumed until end of the "sheet" tag. Therefore the consuming must be suppressed.

However, I don't understand why your code

(defun sheets-new (xlsx)
  "Return sheet informations as list of lists (sheet-name sheet-number sheet-address)."
  (klacks:with-open-source (src (source-entry "xl/workbook.xml" xlsx))
    (loop :for key = (klacks:peek src)
          :while key
          :nconc (if (and (eql key :start-element)
                          (equal (klacks:current-qname src) "sheet"))
                     (list (let* ((sax (klacks:serialize-element src (cxml-xmls:make-xmls-builder)))
                                  (attributes (cadr sax)))
                             (list (cadr (assoc "name" attributes :test #'equal))
                                   (parse-integer (cadr (assoc "sheetId" attributes :test #'equal)))
                                   (concatenate 'string
                                                "xl/worksheets/sheet"
                                                (cadr (assoc "sheetId" attributes :test #'equal))
                                                ".xml"))))
                     (progn
                       (klacks:consume src)
                       nil)))))

is equivalent to mine ...

Can you explain how your code works?