XSLT-эквивалент для JSON - PullRequest
       97

XSLT-эквивалент для JSON

370 голосов
/ 24 октября 2009

Существует ли XSLT эквивалент для JSON? Что-то, что позволяет мне делать преобразования в JSON, как XSLT в XML.

Ответы [ 24 ]

73 голосов
/ 24 октября 2009

Интересная идея. Некоторые поиски в Google дали несколько интересных страниц, в том числе:

Надеюсь, это поможет.

66 голосов
/ 02 июля 2013

Попробуйте JOLT . Это библиотека преобразования JSON в JSON, написанная на Java.

Он был создан специально потому, что мы не хотели играть в игру "JSON -> XML -> XSLT -> XML -> JSON", и использование шаблона для любого достаточно сложного преобразования невозможно.

54 голосов
/ 27 февраля 2018

XSLT-эквиваленты для JSON - список кандидатов (инструменты и спецификации)

Инструменты

  1. XSLT

    Вы можете использовать XSLT для JSON с целью fn: json-to-xml .

    В этом разделе описываются средства, позволяющие обрабатывать данные JSON с использованием XSLT.

  2. JQ

    jq подобен sed для данных JSON - вы можете использовать его для нарезки, фильтрации, отображения и преобразования структурированных данных с той же легкостью, с которой sed, awk, grep и friends позволяют вам играть с текстом. Есть инсталляционные пакеты для разных ОС.

  3. * 1033 Дж *

    JJ - это утилита командной строки, которая обеспечивает быстрый и простой способ извлечения или обновления значений из документов JSON. Он работает на GJSON и SJSON под капотом.

  4. FX

    Средство обработки JSON из командной строки

    • Не нужно изучать новый синтаксис
    • Простой JavaScript
    • Форматирование и выделение
    • Автономный двоичный файл
  5. JL

    jl ("JSON lambda") - крошечный функциональный язык для запросов и управления JSON.

  6. толчок

    Библиотека преобразования JSON в JSON, написанная на Java, где «спецификация» для преобразования сама является документом JSON.

  7. Грон

    Сделайте JSON разборчивым! gron преобразует JSON в отдельные назначения, чтобы упростить поиск того, что вам нужно, и увидеть абсолютный «путь» к нему. Это облегчает исследование API, которые возвращают большие двоичные объекты JSON, но имеют ужасную документацию.

  8. * 1093 JSON *

    json - быстрый CLI-инструмент для работы с JSON. Это однофайловый скрипт node.js без внешних deps (кроме самого node.js).

  9. JSON-е

    JSON-e - это система параметризации структуры данных для встраивания контекста в объекты JSON. Основная идея состоит в том, чтобы рассматривать структуру данных как «шаблон» и преобразовывать ее, используя другую структуру данных в качестве контекста, для создания структуры выходных данных.

  10. JSLT

    JSLT - полный язык запросов и преобразований для JSON. Дизайн языка вдохновлен jq, XPath и XQuery.

  11. json-transforms Последняя фиксация 1 декабря 2017 г.

    Обеспечивает рекурсивный подход сопоставления с образцом для преобразования данных JSON. Преобразования определяются как набор правил, которые соответствуют структуре объекта JSON. Когда происходит совпадение, правило генерирует преобразованные данные, необязательно повторяющиеся для преобразования дочерних объектов.

  12. jsawk Последний коммит 4 марта 2015 г.

    Jsawk похож на awk, но для JSON. Вы работаете с массивом объектов JSON, считываемых из stdin, фильтруете их с помощью JavaScript, чтобы создать массив результатов, который выводится на стандартный вывод.

  13. yate Последний коммит 13 марта 2017 г.

    Тесты могут использоваться как документ https://github.com/pasaran/yate/tree/master/tests

  14. jsonpath-object-transform Последняя фиксация 18 января 2017 г.

    Извлекает данные из литерала объекта с помощью JSONPath и генерирует новые объекты на основе шаблона.

  15. Сшивание Последний коммит 16 сентября 2013

    Сшивание - это библиотека JavaScript, которая позволяет форматировать XSLT для объектов JSON. Вместо использования механизма шаблонов JavaScript и шаблонов text / html Stapling дает вам возможность использовать шаблоны XSLT - загружаемые асинхронно с Ajax, а затем кэшированные на стороне клиента - для анализа ваших источников данных JSON.

Технические характеристики:

  • JsonPointer

    JSON Pointer определяет строковый синтаксис для определения конкретного значения в документе JavaScript Object Notation (JSON).

  • JsonPath

    Выражения JSONPath всегда ссылаются на структуру JSON так же, как выражения XPath используются в сочетании с документом XML

  • JSPath

    JSPath для JSON похож на XPath для XML. "

  • JSONiq

    Основным источником вдохновения для JSONiq является XQuery, который до сих пор оказался успешным и продуктивным языком запросов для полуструктурированных данных

15 голосов
/ 29 сентября 2013

XSLT поддерживает JSON, как видно на http://www.w3.org/TR/xslt-30/#json

XML использует угловые скобки для маркеров-разделителей, JSON использует скобки, квадратные скобки, ... I. e. Меньшее число сравнений распознавания токенов в XML означает, что он оптимизирован для декларативного преобразования, в то время как большее количество сравнений, подобно выражению switch, по соображениям скорости предполагают спекулятивный прогноз ветвления, для которого полезен императивный код в языках сценариев. Как прямое следствие, для различных наборов полуструктурированных данных вы можете захотеть сравнить производительность XSLT и движков javascript как части отзывчивых страниц. Для незначительной полезной нагрузки данных преобразования могут работать так же хорошо с JSON без XML-сериализации. Решение W3 должно основываться на лучшем анализе.

15 голосов
/ 09 мая 2011

Недавно я нашел инструмент, который мне нравится для стилизации JSON: https://github.com/twigkit/tempo. Очень простой в использовании инструмент - на мой взгляд, с ним гораздо проще работать, чем с XSLT - нет необходимости в запросах XPATH.

14 голосов
/ 06 июля 2013

jq - легкий и гибкий процессор командной строки JSON

Он не основан на шаблонах, как XSLT, но более лаконичен. например извлечь поля name и address в массив: [.name, .address]

В учебнике приведен пример преобразования JSON API в Twitter (а в руководстве есть много примеров).

13 голосов
/ 13 февраля 2015

Посмотрите на jsonpath-object-transform

12 голосов
/ 02 ноября 2010

Сказать, что нехватка инструментов говорит о том, что не нужно, значит просто задавать вопрос. То же самое можно применить к поддержке X или Y в Linux (Зачем беспокоиться о разработке качественных драйверов и / или игр для такой малой ОС? И зачем обращать внимание на ОС, для которых не разрабатываются крупные компании, занимающиеся разработкой игр и оборудования?). Вероятно, люди, которым нужно будет использовать XSLT и JSON, в конечном итоге используют несколько тривиальное решение: преобразование JSON в XML. Но ведь это не оптимальное решение?

Если у вас есть собственный формат JSON и вы хотите отредактировать его «wysywyg» в браузере, XSLT будет более чем адекватным решением проблемы. Выполнение этого с традиционным программированием на JavaScript может стать проблемой в заднице.

Фактически, я реализовал подход "каменного века" к XSLT, используя синтаксический анализ подстрок для интерпретации некоторых базовых команд для javascript, таких как вызов шаблона, дочерние процессы и т. Д. Конечно, реализация механизма преобразования с помощью объекта JSON гораздо проще, чем реализовать полноценный анализатор XML для разбора XSLT. Проблема заключается в том, что для использования шаблонов XML для преобразования объекта JSON необходимо проанализировать XML шаблонов.

Чтобы преобразовать объект JSON с помощью XML (или HTML, или текста, или чего-либо еще), вам необходимо тщательно продумать синтаксис и какие специальные символы вам нужно использовать для идентификации команд преобразования. В противном случае вам придётся создавать парсер для вашего собственного языка шаблонов. Пройдя по этому пути, я могу сказать, что это не красиво.

Обновление (12 ноября 2010 г.): после нескольких недель работы над парсером я смог оптимизировать его. Шаблоны предварительно разбираются, а команды хранятся в виде объектов JSON. Правила преобразования также являются объектами JSON, в то время как код шаблона представляет собой смесь HTML и синтаксиса доморощенного кофе, похожего на код оболочки. Мне удалось преобразовать сложный документ JSON в HTML, чтобы создать редактор документов. Код составляет около 1K строк для редактора (это для частного проекта, поэтому я не могу поделиться им) и около 990 строк для кода преобразования JSON (включает в себя команды итерации, простые сравнения, вызов шаблона, сохранение и оценку переменных). Я планирую выпустить его под лицензией MIT. Напишите мне, если хотите принять участие.

10 голосов
/ 27 февраля 2016

Недавно я написал свою собственную маленькую библиотеку, которая пытается остаться как можно ближе к

5.1 Модель обработки (XSLT REC) https://www.w3.org/TR/xslt#section-Processing-Model

как можно (как я мог в любом случае), в нескольких строках кода JavaScript.

Вот несколько не совсем тривиальных примеров использования ...

1. JSON к какой-то-разметке:

Скрипка: https://jsfiddle.net/YSharpLanguage/kj9pk8oz/10

(на основе Пример документа D.1 (XSLT REC) https://www.w3.org/TR/xslt#section-Document-Example)

где это:

var D1document = {
    type: "document", title: [ "Document Title" ],
    "": [
      { type: "chapter", title: [ "Chapter Title" ],
        "": [
        { type: "section", title: [ "Section Title" ],
          "": [
            { type: "para", "": [ "This is a test." ] },
            { type: "note", "": [ "This is a note." ] }
        ] },
        { type: "section", title: [ "Another Section Title" ],
          "": [
            { type: "para", "": [ "This is ", { emph: "another" }, " test." ] },
            { type: "note", "": [ "This is another note." ] }
        ] }
      ] }
    ] };

var D1toHTML = { $: [
  [ [ function(node) { return node.type === "document"; } ],
    function(root) {
      return "<html>\r\n\
  <head>\r\n\
    <title>\r\n\
      {title}\r\n".of(root) + "\
    </title>\r\n\
  </head>\r\n\
  <body>\r\n\
{*}".of(root[""].through(this)) + "\
  </body>\r\n\
</html>";
    }
  ],
  [ [ function(node) { return node.type === "chapter"; } ],
    function(chapter) {
      return "    <h2>{title}</h2>\r\n".of(chapter) + "{*}".of(chapter[""].through(this));
    }
  ],
  [ [ function(node) { return node.type === "section"; } ],
    function(section) {
      return "    <h3>{title}</h3>\r\n".of(section) + "{*}".of(section[""].through(this));
    }
  ],
  [ [ function(node) { return node.type === "para"; } ],
    function(para) {
      return "    <p>{*}</p>\r\n".of(para[""].through(this));
    }
  ],
  [ [ function(node) { return node.type === "note"; } ],
    function(note) {
      return '    <p class="note"><b>NOTE: </b>{*}</p>\r\n'.of(note[""].through(this));
    }
  ],
  [ [ function(node) { return node.emph; } ],
    function(emph) {
      return "<em>{emph}</em>".of(emph);
    }
  ]
] };

console.log(D1document.through(D1toHTML));

... дает:

<html>
  <head>
    <title>
      Document Title
    </title>
  </head>
  <body>
    <h2>Chapter Title</h2>
    <h3>Section Title</h3>
    <p>This is a test.</p>
    <p class="note"><b>NOTE: </b>This is a note.</p>
    <h3>Another Section Title</h3>
    <p>This is <em>another</em> test.</p>
    <p class="note"><b>NOTE: </b>This is another note.</p>
  </body>
</html>

и

2. JSON к JSON:

Скрипка: https://jsfiddle.net/YSharpLanguage/ppfmmu15/10

где это:

// (A "Company" is just an object with a "Team")
function Company(obj) {
  return obj.team && Team(obj.team);
}

// (A "Team" is just a non-empty array that contains at least one "Member")
function Team(obj) {
  return ({ }.toString.call(obj) === "[object Array]") &&
         obj.length &&
         obj.find(function(item) { return Member(item); });
}

// (A "Member" must have first and last names, and a gender)
function Member(obj) {
  return obj.first && obj.last && obj.sex;
}

function Dude(obj) {
  return Member(obj) && (obj.sex === "Male");
}

function Girl(obj) {
  return Member(obj) && (obj.sex === "Female");
}

var data = { team: [
  { first: "John", last: "Smith", sex: "Male" },
  { first: "Vaio", last: "Sony" },
  { first: "Anna", last: "Smith", sex: "Female" },
  { first: "Peter", last: "Olsen", sex: "Male" }
] };

var TO_SOMETHING_ELSE = { $: [

  [ [ Company ],
    function(company) {
      return { some_virtual_dom: {
        the_dudes: { ul: company.team.select(Dude).through(this) },
        the_grrls: { ul: company.team.select(Girl).through(this) }
      } }
    } ],

  [ [ Member ],
    function(member) {
      return { li: "{first} {last} ({sex})".of(member) };
    } ]

] };

console.log(JSON.stringify(data.through(TO_SOMETHING_ELSE), null, 4));

... дает:

{
    "some_virtual_dom": {
        "the_dudes": {
            "ul": [
                {
                    "li": "John Smith (Male)"
                },
                {
                    "li": "Peter Olsen (Male)"
                }
            ]
        },
        "the_grrls": {
            "ul": [
                {
                    "li": "Anna Smith (Female)"
                }
            ]
        }
    }
}

3. XSLT против JavaScript:

JavaScript-эквивалент ...

XSLT 3.0 REC Раздел 14.4 Пример: группировка узлов на основе общих значений

(по адресу: http://jsfiddle.net/YSharpLanguage/8bqcd0ey/1)

Cf. https://www.w3.org/TR/xslt-30/#grouping-examples

где ...

var cities = [
  { name: "Milano",  country: "Italia",      pop: 5 },
  { name: "Paris",   country: "France",      pop: 7 },
  { name: "München", country: "Deutschland", pop: 4 },
  { name: "Lyon",    country: "France",      pop: 2 },
  { name: "Venezia", country: "Italia",      pop: 1 }
];

/*
  Cf.
  XSLT 3.0 REC Section 14.4
  Example: Grouping Nodes based on Common Values

  https://www.w3.org/TR/xslt-30/#grouping-examples
*/
var output = "<table>\r\n\
  <tr>\r\n\
    <th>Position</th>\r\n\
    <th>Country</th>\r\n\
    <th>City List</th>\r\n\
    <th>Population</th>\r\n\
  </tr>{*}\r\n\
</table>".of
  (
    cities.select().groupBy("country")(function(byCountry, index) {
      var country = byCountry[0],
          cities = byCountry[1].select().orderBy("name");
      return "\r\n\
  <tr>\r\n\
    <td>{position}</td>\r\n\
    <td>{country}</td>\r\n\
    <td>{cities}</td>\r\n\
    <td>{population}</td>\r\n\
  </tr>".
        of({ position: index + 1, country: country,
             cities: cities.map(function(city) { return city.name; }).join(", "),
             population: cities.reduce(function(sum, city) { return sum += city.pop; }, 0)
           });
    })
  );

... дает:

<table>
  <tr>
    <th>Position</th>
    <th>Country</th>
    <th>City List</th>
    <th>Population</th>
  </tr>
  <tr>
    <td>1</td>
    <td>Italia</td>
    <td>Milano, Venezia</td>
    <td>6</td>
  </tr>
  <tr>
    <td>2</td>
    <td>France</td>
    <td>Lyon, Paris</td>
    <td>9</td>
  </tr>
  <tr>
    <td>3</td>
    <td>Deutschland</td>
    <td>München</td>
    <td>4</td>
  </tr>
</table>

4. JSONiq против JavaScript:

JavaScript-эквивалент ...

Примеры использования JSONiq Раздел 1.1.2. Группировка запросов для JSON

(по адресу: https://jsfiddle.net/YSharpLanguage/hvo24hmk/3)

Cf. http://jsoniq.org/docs/JSONiq-usecases/html-single/index.html#jsongrouping

где ...

/*
  1.1.2. Grouping Queries for JSON
  http://jsoniq.org/docs/JSONiq-usecases/html-single/index.html#jsongrouping
*/
var sales = [
  { "product" : "broiler", "store number" : 1, "quantity" : 20  },
  { "product" : "toaster", "store number" : 2, "quantity" : 100 },
  { "product" : "toaster", "store number" : 2, "quantity" : 50 },
  { "product" : "toaster", "store number" : 3, "quantity" : 50 },
  { "product" : "blender", "store number" : 3, "quantity" : 100 },
  { "product" : "blender", "store number" : 3, "quantity" : 150 },
  { "product" : "socks", "store number" : 1, "quantity" : 500 },
  { "product" : "socks", "store number" : 2, "quantity" : 10 },
  { "product" : "shirt", "store number" : 3, "quantity" : 10 }
];

var products = [
  { "name" : "broiler", "category" : "kitchen", "price" : 100, "cost" : 70 },
  { "name" : "toaster", "category" : "kitchen", "price" : 30, "cost" : 10 },
  { "name" : "blender", "category" : "kitchen", "price" : 50, "cost" : 25 },
  {  "name" : "socks", "category" : "clothes", "price" : 5, "cost" : 2 },
  { "name" : "shirt", "category" : "clothes", "price" : 10, "cost" : 3 }
];

var stores = [
  { "store number" : 1, "state" : "CA" },
  { "store number" : 2, "state" : "CA" },
  { "store number" : 3, "state" : "MA" },
  { "store number" : 4, "state" : "MA" }
];

var nestedGroupingAndAggregate = stores.select().orderBy("state").groupBy("state")
( function(byState) {
    var state = byState[0],
        stateStores = byState[1];
    byState = { };
    return (
      (
        byState[state] =
        products.select().orderBy("category").groupBy("category")
        ( function(byCategory) {
            var category = byCategory[0],
                categoryProducts = byCategory[1],
                categorySales = sales.filter(function(sale) {
                  return stateStores.find(function(store) { return sale["store number"] === store["store number"]; }) &&
                         categoryProducts.find(function(product) { return sale.product === product.name; });
                });
            byCategory = { };
            return (
              (
                byCategory[category] =
                categorySales.select().orderBy("product").groupBy("product")
                ( function(byProduct) {
                    var soldProduct = byProduct[0],
                        soldQuantities = byProduct[1];
                    byProduct = { };
                    return (
                      (
                        byProduct[soldProduct] =
                        soldQuantities.reduce(function(sum, sale) { return sum += sale.quantity; }, 0)
                      ),
                      byProduct
                    );
                } ) // byProduct()
              ),
              byCategory
            );
        } ) // byCategory()
      ),
      byState
    );
} ); // byState()

... дает:

[
  {
    "CA": [
      {
        "clothes": [
          {
            "socks": 510
          }
        ]
      },
      {
        "kitchen": [
          {
            "broiler": 20
          },
          {
            "toaster": 150
          }
        ]
      }
    ]
  },
  {
    "MA": [
      {
        "clothes": [
          {
            "shirt": 10
          }
        ]
      },
      {
        "kitchen": [
          {
            "blender": 250
          },
          {
            "toaster": 50
          }
        ]
      }
    ]
  }
]

Также полезно преодолеть ограничения JSONPath в отношении. запрос к оси предка, как это было поставлено , этот вопрос SO (и, конечно, другие).

Например, как получить скидку на продуктовый продукт, зная идентификатор бренда, в

{
 "prods": [
    {
        "info": {
              "rate": 85
                },
        "grocery": [
                 {
                  "brand": "C",
                  "brand_id": "984"
                 },
                 {
                  "brand": "D",
                  "brand_id": "254"
                 }
                 ],
         "discount": "15"
    },
    {
        "info": {
              "rate": 100
                },
        "grocery": [
                 {
                  "brand": "A",
                  "brand_id": "983"
                 },
                 {
                  "brand": "B",
                  "brand_id": "253"
                 }
                 ],
         "discount": "20"
     }
 ]
}

Возможное решение:

var products = {
     "prods": [
        {
            "info": {
                  "rate": 85
                    },
            "grocery": [
                     {
                      "brand": "C",
                      "brand_id": "984"
                     },
                     {
                      "brand": "D",
                      "brand_id": "254"
                     }
                     ],
             "discount": "15"
        },
        {
            "info": {
                  "rate": 100
                    },
            "grocery": [
                     {
                      "brand": "A",
                      "brand_id": "983"
                     },
                     {
                      "brand": "B",
                      "brand_id": "253"
                     }
                     ],
             "discount": "20"
         }
     ]
};

function GroceryItem(obj) {
  return (typeof obj.brand === "string") && (typeof obj.brand_id === "string");
}

    // last parameter set to "true", to grab all the "GroceryItem" instances
    // at any depth:
var itemsAndDiscounts = [ products ].nodeset(GroceryItem, true).
    map(
      function(node) {
        var item = node.value, // node.value: the current "GroceryItem" (aka "$.prods[*].grocery[*]")

            discount = node.parent. // node.parent: the array of "GroceryItem" (aka "$.prods[*].grocery")
                       parent. // node.parent.parent: the product (aka "$.prods[*]")
                       discount; // node.parent.parent.discount: the product discount

        // finally, project into an easy-to-filter form:
        return { id: item.brand_id, discount: discount };
      }
    ),
    discountOfItem983;

discountOfItem983 = itemsAndDiscounts.
  filter
  (
    function(mapped) {
      return mapped.id === "983";
    }
  )
  [0].discount;

console.log("Discount of #983: " + discountOfItem983);

... что дает:

Discount of #983: 20

НТН,

10 голосов
/ 10 июля 2016

Есть сейчас! Недавно я создал библиотеку json-transforms , специально для этой цели:

https://github.com/ColinEberhardt/json-transforms

Используется комбинация JSPath , DSL, смоделированный на XPath, и подход рекурсивного сопоставления с образцом, вдохновленный XSLT.

Вот быстрый пример. Учитывая следующий объект JSON:

const json = {
  "automobiles": [
    { "maker": "Nissan", "model": "Teana", "year": 2011 },
    { "maker": "Honda", "model": "Jazz", "year": 2010 },
    { "maker": "Honda", "model": "Civic", "year": 2007 },
    { "maker": "Toyota", "model": "Yaris", "year": 2008 },
    { "maker": "Honda", "model": "Accord", "year": 2011 }
  ]
};

Вот трансформация:

const jsont = require('json-transforms');
const rules = [
  jsont.pathRule(
    '.automobiles{.maker === "Honda"}', d => ({
      Honda: d.runner()
    })
  ),
  jsont.pathRule(
    '.{.maker}', d => ({
      model: d.match.model,
      year: d.match.year
    })
  ),
  jsont.identity
];

const transformed  = jsont.transform(json, rules);

Который выводит следующее:

{
  "Honda": [
    { "model": "Jazz", "year": 2010 },
    { "model": "Civic", "year": 2007 },
    { "model": "Accord", "year": 2011 }
  ]
}

Это преобразование состоит из трех правил. Первый соответствует любому автомобилю, который сделан Honda, испускает объект со свойством Honda, затем рекурсивно совпадает. Второе правило сопоставляет любой объект со свойством maker, выводя свойства model и year. Финальным является преобразование идентичности, которое рекурсивно совпадает.

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