我的xml没有使用属性和名称空间。标签可以嵌套。我想把它解析成Clojure地图。
我希望标签名称是键。如果是节点,则值为嵌套映射;对于叶子,值为文本。
最简单的方法是什么?
答案 0 :(得分:2)
我用这个:clojure.xml/parse
您可能会发现的问题是输出的结构不是您想要的地图。您将不得不从clojure.xml地图到地图进行某种转换。
我尝试创建某种通用翻译器,但我最终意识到我需要一些定义xml(模式)结构的东西。然后我找了一个Clojure项目,它使用xsd为我转换xml。当时没有任何好的支持。所以我最后只是编写了Clojure来进行转换,这要感谢Clojure真的很容易(而且我更喜欢写Clojure而不是xsd)。这解释了缺少Clojure xml架构转换库。
在我脑海中浮现的东西,我认为如果可行的话会非常酷或有趣,可以在prismatic/schema中定义架构,并使用该架构来转换地图。然后,您还可以从棱镜中获得验证和功能。
答案 1 :(得分:1)
我为.NET序列化程序生成了很多XML,用于嵌套类,包含值,数组等。只使用实体和内容。
对我来说,使用:tag:content等的默认clojure XML结构使用起来相当混乱,如果是深层对象,很容易混淆。
我使用此函数创建一个简单的中间表示,然后我可以根据属性的类型进一步细化。
我首先使用clojure.data.xml / parse解析字符串或byte [],然后调用keep-tag-and-contents-prepare-leafs
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rd="http://www.w3schools.com/RedsDevils">
<xsl:output doctype-system="about:legacy-compat" method="html"/>
<xsl:template match="/">
<html>
<HEAD>
<link href="style.css" rel="stylesheet" type="text/css"/>
<link href='https://fonts.googleapis.com/css?family=Caudex:400,700' rel='stylesheet' type='text/css'/>
<script src="js/jquery.js" type="text/javascript"></script>
<!--BOOTSTRAP!! -->
<!-- Latest compiled and minified CSS -->
<link crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" rel="stylesheet"/>
<!-- Optional theme -->
<link crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" rel="stylesheet"/>
<!-- Latest compiled and minified JavaScript -->
<script crossorigin="anonymous" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<!-- BOOTSTRAP END -->
<title>GRY!! :D
</title>
</HEAD>
<BODY>
<div id="bg"></div>
<div id="container">
<h1 id="title">
GRY 2015 ROKU
</h1>
<div id="header">
<div class="row">
<div class="col-md-4">
<div class="menuelm" id="All">
<h3>Wszystkie tytuły</h3>
<a class="link" href="#">Wyświetl</a>
</div>
</div>
<div class="col-md-4">
<div class="menuelm" id="Gat">
<h3>Filtruj gatunek:</h3>
<select>
<option>FPS</option>
<option>RPG</option>
<option>Strategia</option>
<option>Bijatyka</option>
<option>Horror</option>
<option>Wyscigi</option>
</select>
<a class="gatlink" href="#">Wyświetl</a>
</div>
</div>
<div class="col-md-4">
<div class="menuelm" id="Sys">
<h3>Filtruj Konsole:</h3>
<div class="row systems">
<a href="#pc"><img alt="pc" src="img/sym/pc.jpg"/></a>
<a href="#xbo"><img alt="xbox" src="img/sym/xbox.png"/></a>
<a href="#ps"><img alt="ps4" src="img/sym/ps4.jpg"/></a>
</div>
</div>
</div>
</div>
</div>
<!--HEADER END -->
<div id="tablecover">
<xsl:call-template name="all"/>
<script src="js/gry.js" type="text/javascript"></script>
</div>
</div>
<!--container end!-->
<div style="clear: both"></div>
<footer>
<h3>Projekt Alan Krygowski</h3>
</footer>
</BODY>
</html>
</xsl:template>
<xsl:template name="all">
<table class="tablesorter" id="myTable">
<thead>
<tr>
<td>
<div>
<p>Nazwa</p>
</div>
</td>
<td>
<div>
<p>Gatunek</p>
</div>
</td>
<td>
<div>
<p>Producent</p>
</div>
</td>
<td>
<div>
<p>Wydawca</p>
</div>
</td>
<td>
<div>
<p>Cena</p>
</div>
</td>
<td>
<div>
<p>Data Wydania</p>
</div>
</td>
<td>
<div>
<p>Metacritic</p>
</div>
</td>
<td>
<div>
<p>PC</p>
</div>
</td>
<td>
<div>
<p>XBOX</p>
</div>
</td>
<td>
<div>
<p>PS4</p>
</div>
</td>
</tr>
</thead>
<tbody>
<!-- <xsl:for-each select="gatunek/gra[../@id='FPS'] | gatunek/gra[../@id='Strategia']">-->
<xsl:for-each select="rd:gry/rd:gatunek/rd:gra">
<tr class="{../@id} ">
<td>
<div>
<p><xsl:value-of select="@nazwa"/></p>
</div>
</td>
<td>
<div>
<p><xsl:value-of select="../@id"/></p>
</div>
</td>
<td>
<div>
<p><xsl:value-of select="rd:producent"/></p>
</div>
</td>
<td>
<div>
<p><xsl:value-of select="rd:wydawca"/></p>
</div>
</td>
<td>
<div>
<xsl:choose>
<xsl:when test="not(rd:cena)">
<p>brak danych</p>
</xsl:when>
<xsl:otherwise>
<p><xsl:value-of select="rd:cena"/>PLN</p>
</xsl:otherwise>
</xsl:choose>
</div>
</td>
<td>
<div>
<xsl:choose>
<xsl:when test="not(rd:data_wydania)">
<p>brak danych</p>
</xsl:when>
<xsl:otherwise>
<p><xsl:value-of select="rd:data_wydania"/></p>
</xsl:otherwise>
</xsl:choose>
</div>
</td>
<td>
<div>
<xsl:choose>
<xsl:when test="not(rd:metacritic)">
<p>brak danych</p>
</xsl:when>
<xsl:otherwise>
<p><xsl:value-of select="rd:metacritic"/>/100</p>
</xsl:otherwise>
</xsl:choose>
</div>
</td>
<!-- OD AUTORA
Wczesniej, do tych trzech punktow, xsl zawieral zapytanie if odpowiednio
dostosowujace rodzaj klasy ktora miala byc wstawiona. Zostalo to zamienione
poniewaz przez dopisywanie klasy zmniejszamy niepotrzebne zablocenie strony -->
<td>
<div class="pc {@PC}"></div>
</td>
<td>
<div class="xbo {@XBOXONE}"></div>
</td>
<td>
<div class="ps {@PS4}"></div>
</td>
</tr>
<div class="underbox">
<img alt="coverart">
<xsl:attribute name="src">
<xsl:value-of select="rd:cover"/>
</xsl:attribute>
</img>
<div class="about">
<p><xsl:value-of select="rd:opis"/></p>
</div>
</div>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
我得到这样的结构:
(defn keep-tag-and-contents-prepare-leafs
"Simplify the clj-xml structure, I am only interested in :tag and :content"
[xml]
(if (map? xml)
[(:tag xml) (keep-tag-and-contents-prepare-leafs (:content xml))]
(if (seq? xml)
(if (map? (first xml))
(for [x xml] (keep-tag-and-contents-prepare-leafs x))
(do
;; we are at the bottom of the xml
(assert (<= (count xml) 1) "Leafs should be empty or single value")
(if (empty? xml) nil (first xml)))
)
;; we should never end up here, since we do a look-a-head on the level above the leafs
(assert false))))
可以轻松进一步处理,只需打开矢量?和seq?
这个中间表示也非常紧凑,因此很容易打印东西,在前面加上引号,并创建单元测试。