Опыт использования xml2json-xslt

03.07.2013г. // Рубрики: web, Рецепты
xsl:chooseXSLT - схема выбора
Обычно, до этого, я в подобных ситуациях обходился "ручным" xslt-преобразованием xml в json, поскольку xml-ответы были статичными и простенькими. Либо отдавал не json-ом, а html. Но в данной задаче требовался именно json и оказалось, что в атрибутах узлов может содержаться всякая хрень, вполне способная выйти боком. Короче говоря, мне потребовался некий xslt-фреймворк, берущий на себя обязательства по экранированию, наведению красОт и прочим прелестям.
Итак, гугление быстро привело к проекту  xml2json-xslt. В скачанном архиве (последняя версия за декабрь 2006 года) меня заинтересовал (помимо readme) один файл: xml2json.xslt - он то мне и нужен. Тестовые xml-ли из архива он бодро обработал (запускал я через перловый модуль XML::LibXSLT). Однако, при попытки наложить xslt-преобразование на свой xml, получал полупустой json.
Мой xml имеет примерно такой вид:
<page>
    <plugin name="auth" email="admin@kremlin.ru" id="1" nickname="BOSS" status="1"/>
</page>
Краткий анализ xml2json.xslt привёл меня к мысли, что, вместо этого, скрипт хотел бы видеть мой xml примерно так:
<auth>
    <nickname>BOSS</nickname>
    <email>admin@kremlin.ru</email>
    <status>1</status>
    <id>1</id>
</auth>
Тогда преобразования проходят "на ура". Но не буду же я переделывать весь xml-output только ради одного сомнительного json-а?!!
Вобщем, поисследовал, почитал Интернеты (отдельно спасибо сайту Тёмы Лебедева за опус про временные деревья - очень пригодилось). Сухой остаток следующий.
В скрипте xml2json.xslt комментируем последний кусок таким образом:
<!-- convert root element to an anonymous container -->
<!--
  <xsl:template match="/">
    <xsl:apply-templates select="node()"/>
  </xsl:template>
-->
поскольку вызов корня будем делать самостоятельно.
Пишем свой xsl-файл:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common">
<xsl:output indent="no" omit-xml-declaration="yes" method="text" encoding="UTF-8"
    media-type="text/x-json"/>

<xsl:include href="xml2json.xslt" />

<xsl:variable name="tmptree">
    <auth>
        <nickname><xsl:value-of select="/page/plugin[@name='auth']/@nickname" /></nickname>
        <email><xsl:value-of select="/page/plugin[@name='auth']/@email" /></email>
        <status><xsl:value-of select="/page/plugin[@name='auth']/@status" /></status>
        <id><xsl:value-of select="/page/plugin[@name='auth']/@id" /></id>
    </auth>
</xsl:variable>

<xsl:template match="/">
    <xsl:apply-templates select="exsl:node-set($tmptree)/auth"/>
</xsl:template>
</xsl:stylesheet>
По-сути, мы формируем на лету новый xml (tmptree), который библиотека способна переварить, и подсовываем его вместо исходного корня.

Рубрики