2009-07-28 13 views
64

No encuentro ninguna información sobre cómo analizar documentos XML y acceder a elementos.Clojure XML Parsing

he encontrado dos maneras de analizar el documento XML

(clojure.zip/xml-zip (clojure.xml/parse file)) 

y

(parse-seq file) 

pero yo puedo encontrar ninguna información sobre cómo procesar la estructura resultante?

El archivo de origen hace referencia a zip-query.clj sobre cómo consultar el resultado, pero parece que también falta.

+2

Los ejemplos de zip-query.clj se pueden encontrar en xml_test.clj que se encuentra en src/test/clojure/clojure/datos/zip en el repositorio github para clojure.data.zip –

+0

divertido, pregunté esto como bien, y obtuve excelentes respuestas de algunas de las personas más útiles en SO. Sin embargo, incluso después de ejecutar los datos analizados resultantes.xml a través de una de las sugerencias, la estructura resultante todavía no tiene mucho sentido para mí. Voy a ver tu xml-zip, a menos que data.xml sea su sucesor. – octopusgrabbus

Respuesta

81

Suponga que tiene la siguiente XML para analizar en su archivo:

<high-node> 
    <low-node>my text</low-node> 
</high-node> 

se carga clojure.xml:

user=> (use 'clojure.xml) 

cuando se analiza, el código XML tendrá la siguiente estructura:

{:tag :high-node, :attrs nil, :content [{:tag :low-node, :attrs nil, :content ["my text"]}]} 

y luego puede buscar el contenido del archivo para obtener el contenido de th e low-node:

user=> (for [x (xml-seq 
       (parse (java.io.File. file))) 
       :when (= :low-node (:tag x))] 
     (first (:content x))) 

("my text") 

Del mismo modo, si quería tener acceso a toda la lista de información de bajo nodo, que cambiaría el :when predicado a (= (:high-node (:tag x))):

user=> (for [x (xml-seq 
       (parse (java.io.File. file))) 
       :when (= :high-node (:tag x))] 
     (first (:content x))) 

({:tag :low-node, :attrs nil, :content ["my text"]}) 

Esto funciona porque las palabras clave puede operar como funciones. Ver Questions about lists and other stuff in Clojure y Data Structures: Keywords

+0

¡Excelente respuesta! –

+0

¡Muy buena explicación! Voy a intentar esto. – Ralph

+0

(descargo de responsabilidad: soy un recién llegado) Pero encontré que esto funcionó para mí en el REPL, y no pude hacer que funcionara en un archivo (mi ignorancia es la culpable). El archivo clojure.data.zip.xml funcionó para mí en un archivo sin modificaciones. – wonderfulthunk

52

La respuesta anterior funciona, pero me parece que sea mucho más fácil de usar clojure.data.zip.xml (solía ser clojure-contrib.zip-filter.xml antes de Clojure 1.3).

archivo:

myfile.xml:

<songs> 
    <track id="t1"><name>Track one</name></track> 
    <track id="t2"><name>Track two</name></track> 
</songs> 

código:

; Clojure 1.3 
(ns example 
    (:use [clojure.data.zip.xml :only (attr text xml->)]) ; dep: see below 
    (:require [clojure.xml :as xml] 
      [clojure.zip :as zip])) 

(def xml (xml/parse "myfile.xml")) 
(def zipped (zip/xml-zip xml)) 
(xml-> zipped :track :name text)  ; ("Track one" "Track two") 
(xml-> zipped :track (attr :id))  ; ("t1" "t2") 

Desafortunadamente, usted tiene que tirar en una dependencia de data.zip para conseguir esta funcionalidad de lectura/filtro agradable. Vale la pena la dependencia :) En lein sería (a partir del 17-Ago-2013):

[org.clojure/data.zip "0.1.1"] 

Y en cuanto a documentación para data.zip.xml ... Sólo miro el relativamente pequeño archivo de origen a here mira lo que es posible Otra buena respuesta SO here, también.

+2

Esto funcionó muy bien para mí en un proyecto en el que estoy trabajando. – wonderfulthunk

+1

No entiendo por qué (xml-> zip: track: name text) funcionará, pero (xml-> zip: songs: track: name text) no funcionará o (xml-> zip: name text) no funcionará. No estoy seguro de por qué tiene que especificar un cierto nivel de anidación de las etiquetas, pero no otras. –

+0

@RyanMoore es una [cremallera] (http://www.haskell.org/haskellwiki/Zipper), las cremalleras son sensibles al contexto porque tienen un nodo actual, y debe entregarles las instrucciones de cruce apropiadamente en relación con ese nodo de contexto. Aparentemente, el nodo de contexto predeterminado es root, que tiene sentido. –