clojure - 将没有属性的xml解析为地图的简单方法

时间:2016-01-13 16:28:54

标签: xml clojure

我的xml没有使用属性和名称空间。标签可以嵌套。我想把它解析成Clojure地图。

我希望标签名称是键。如果是节点,则值为嵌套映射;对于叶子,值为文本。

最简单的方法是什么?

2 个答案:

答案 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?

这个中间表示也非常紧凑,因此很容易打印东西,在前面加上引号,并创建单元测试。