парсинг XML в clojure - PullRequest
       0

парсинг XML в clojure

5 голосов
/ 24 июня 2011

Я новичок в clojure, поэтому, пожалуйста, потерпите меня.У меня есть XML, который выглядит следующим образом

<?xml version="1.0" encoding="UTF-8"?>
<XVar Id="cdx9" Type="Dictionary">
  <XVar Id="Base.AccruedPremium" Type="Multi" Value="" Rows="1" Columns="1">
    <Row Id="0">
      <Col Id="0" Type="Num" Value="0"/>
    </Row>
  </XVar>
  <XVar Id="TrancheAnalysis.IndexDuration" Type="Multi" Value="" Rows="1" Columns="1">
    <Row Id="0">
      <Col Id="0" Type="Num" Value="3.4380728252313069"/>
    </Row>
  </XVar>
  <XVar Id="TrancheAnalysis.IndexLevel01" Type="Multi" Value="" Rows="1" Columns="1">
    <Row Id="0">
      <Col Id="0" Type="Num" Value="30693.926279941188"/>
    </Row>
  </XVar>
  <XVar Id="TrancheAnalysis.TrancheDelta" Type="Multi" Value="" Rows="1" Columns="1">
    <Row Id="0">
      <Col Id="0" Type="Num" Value="8.9304387917502073"/>
    </Row>
  </XVar>
  <XVar Id="TrancheAnalysis.TrancheDuration" Type="Multi" Value="" Rows="1" Columns="1">
    <Row Id="0">
      <Col Id="0" Type="Num" Value="3.0775955481964035"/>
    </Row>
  </XVar>
</XVar>

И он повторяется.Исходя из этого, я хочу создать CSV-файл с этими столбцами

IndexName,TrancheAnalysis.IndexDuration,TrancheAnalysis.TrancheDuration
cdx9,3.4380728252313069,3.0775955481964035
.........................................
.........................................

. Я могу проанализировать простой XML-файл, такой как

<?xml version="1.0" encoding="UTF-8"?>
<CalibrationData>
  <IndexList>
    <Index>
      <Calibrate>Y</Calibrate>
      <UseClientIndexQuotes>Y</UseClientIndexQuotes>
      <IndexName>HYCDX10</IndexName>
      <Tenor>06/20/2013</Tenor>
      <TenorName>3Y</TenorName>
      <IndexLevels>219.6</IndexLevels>
      <Tranche>Equity0To0.15</Tranche>
      <TrancheStart>0</TrancheStart>
      <TrancheEnd>0.15</TrancheEnd>
      <UseBreakEvenSpread>1</UseBreakEvenSpread>
      <UseTlet>0</UseTlet>
      <IsTlet>0</IsTlet>
      <PctExpectedLoss>0</PctExpectedLoss>
      <UpfrontFee>52.125</UpfrontFee>
      <RunningFee>0</RunningFee>
      <DeltaFee>5.3</DeltaFee>
      <CentralCorrelation>0.1</CentralCorrelation>
      <Currency>USD</Currency>
      <RescalingMethod>PTIndexRescaling</RescalingMethod>
      <EffectiveDate>06/17/2011</EffectiveDate>
    </Index>
  </IndexList>
</CalibrationData>

, с этим кодом

(ns DynamicProgramming
  (:require [clojure.xml :as xml]))
;Get the Input Files
(def calibrationFile "C:/ashwani/Eclipse/HistoricalTrancheAnalysis/src/CalibrationQuotes.xml")
(def mktdataFile "C:/ashwani/Eclipse/HistoricalTrancheAnalysis/src/MarketData.xml")
(def sample "C:/ashwani/Eclipse/HistoricalTrancheAnalysis/src/Sample.xml")

;Parse the Calibration Input File
    (def CalibOp (for [x 
                  (xml-seq 
                    (xml/parse (java.io.File. calibrationFile)))
          :when (or 
                  (= :IndexName (:tag x)) 
                  (= :Tenor (:tag x))
                  (= :UpfrontFee (:tag x))
                  (= :RunningFee (:tag x))
                  (= :DeltaFee (:tag x))
                  (= :IndexLevels (:tag x))
                  (= :TrancheStart (:tag x))
                  (= :TrancheEnd (:tag x))
                 )]
    (first(:content x))))
    (println  CalibOp)

Но второй XML прост;с другой стороны, я не знаю, как перебрать вложенную структуру первого примера XML и извлечь нужную информацию.

Любая помощь будет отличной.

1 Ответ

9 голосов
/ 24 июня 2011

Я бы использовал data.zip (ранее - clojure.contrib.zip-filter). Он предоставляет много возможностей для xml-разбора и легко может выполнять выражения, подобные xpath. README описывает ее как систему фильтрации деревьев и, в частности, деревьев XML .

Ниже приведен пример кода для создания "строки" для файла CSV. Строка является картой имени столбца со значением атрибута.

(ns work 
    (:require [clojure.xml :as xml]
              [clojure.zip :as zip]
              [clojure.contrib.zip-filter.xml :as zf]))

; create a zip from the xml file
(def zip (zip/xml-zip (xml/parse "data.xml")))

; pulls out a list of all of the root "Id" attribute values
(zf/xml-> zip (zf/attr :Id))

(defn value [xvar-zip]
  "Finds the id and value for a particular element"
  (let [id (-> xvar-zip zip/node :attrs :Id) ; manual access
        value (zf/xml1-> xvar-zip ; use xpath like expression to pull value out
                         :Row ; need the row element
                         :Col ; then the column element
                         (zf/attr :Value))] ; and finally pull the Value out
    {id value}))

; gets the "column-value" pair for a single column
(zf/xml1-> zip
           (zf/attr= :Id "cdx9") ; filter on id "cdx9" 
           :XVar ; filter on XVars under it 
           (zf/attr= :Id "TrancheAnalysis.IndexDuration") ; filter on id
           value) ; apply the value function on the result of above

; creates a map of every column key to it's corresponding value
(apply merge (zf/xml-> zip (zf/attr= :Id "cdx9") :XVar value))

Я не уверен, как xml будет работать с несколькими словарями XVar, так как это корневой элемент. Если вам нужно, одна из других функций, которая полезна для этого типа работы, - это mapcat, которая cat содержит все значения, возвращаемые функцией отображения.

В тестовом источнике есть еще несколько примеров .

Еще одна важная рекомендация, которую я имею, - убедиться, что вы используете много мелких функций. Вам будет намного легче отлаживать, тестировать и работать с ними.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...