XSLT tương đương với JSON


14

Tôi đã quan tâm đến việc tìm kiếm (hoặc nếu cần phát triển) một XSLT tương đương với JSON.

Vì tôi không tìm thấy bất kỳ, tôi đã xem xét ngôn ngữ truy vấn có thể sử dụng để khớp các đường dẫn JSON để áp dụng các mẫu (từ JavaScript) khi có một kết quả khớp (có lẽ chỉ cần kiểm tra một mảng các mẫu phù hợp theo thứ tự và dừng lại ở mẫu đầu tiên phù hợp, mặc dù cho phép tương đương với xsl: application-samples để giữ mẫu cho trẻ em).

Tôi biết về JSONPath, JSONQuery và RQL như các ngôn ngữ truy vấn JSON (mặc dù tôi không hoàn toàn rõ ràng về việc RQL có hỗ trợ các đường dẫn tuyệt đối và tương đối hay không). Bất kỳ đề xuất về các yếu tố để xem xét và lợi thế tương đối của mỗi đối với việc sử dụng như vậy.


Chỉ là một suy nghĩ ngẫu nhiên, JavaScript và Mustache / Tay cầm có thể? :)
Knerd

Cảm ơn, nhưng tôi quan tâm hơn đến việc sử dụng một cách tiếp cận chuẩn (ví dụ: ít nhất một cách có tiềm năng, được cho rằng các biểu thức đường dẫn JSON chung sẽ là một phương tiện được công nhận chung về tham chiếu JSON so với một số cú pháp cụ thể cho thư viện).
Brett Zamir


1
Tôi cũng thấy điều này thú vị: json-template.googlecode.com/svn/trunk/doc/ dọa
Robert Harvey

Tôi đã thực hiện Json -> XML -> XSLT -> Json trước đây - nó hoạt động tốt, ngay cả khi đó không phải là giải pháp hiệu quả nhất,
user2813274

Câu trả lời:


27

XML: XSLT :: JSON: x . X là gì?

Câu trả lời dễ hiểu nhất sẽ là x = JavaScript. Mặc dù bạn có thể làm một trường hợp cho điều này, nó cảm thấy không hài lòng. Mặc dù XSLT đã hoàn tất về mặt kỹ thuật , vẫn có sự tương ứng kém giữa phong cách khai báo của XSLT và các kiểu bắt buộc hoặc chức năng bắt buộc hơn trong JavaScript.

Có một vài ngôn ngữ truy vấn JSON độc lập, như JSONPath , JSONiqRQL có thể thay thế cho nền tảng trung gian của XML: XPath :: JSON: y (hoặc có thể, XQuery chứ không phải XPath). Và mọi cơ sở dữ liệu tài liệu tập trung vào JSON đều có ngôn ngữ truy vấn liên quan đến JSON .

Nhưng thực tế là, mặc dù có một vài ứng cử viên cho vị trí XSLT đầy đủ, chẳng hạn như SpahQL , nhưng không có tương đương JSON được chấp nhận rộng rãi, được hỗ trợ rộng rãi cho XSLT.

Tại sao?

Với tất cả JSON trên thế giới, tại sao không có tương tự (trực tiếp hơn) với XSLT? Bởi vì nhiều nhà phát triển xem XSLT là một thử nghiệm thất bại. Bất kỳ công cụ tìm kiếm nào cũng sẽ dẫn đến các trích dẫn như "XSLT là một thất bại bao trùm trong nỗi đau". Những người khác đã lập luận rằng nếu nó chỉ được định dạng tốt hơn, nó sẽ phổ biến hơn. Nhưng sự quan tâm đến XSLT nói chung đã giảm dần trong những năm qua . Nhiều công cụ hỗ trợ nó chỉ hỗ trợ phiên bản 1.0 , đây là thông số kỹ thuật năm 1999. Thông số kỹ thuật mười lăm tuổi? Có một thông số 2.0 mới hơn nhiều và nếu mọi người nhiệt tình với XSLT, nó sẽ được hỗ trợ. Không phải vậy.

Bởi và các nhà phát triển lớn đã chọn xử lý và chuyển đổi các tài liệu XML bằng mã chứ không phải các mẫu chuyển đổi. Do đó, không có gì ngạc nhiên khi làm việc với JSON, họ cũng thường chọn cách làm điều đó bằng ngôn ngữ bản địa của họ, thay vì thêm một hệ thống chuyển đổi "nước ngoài" bổ sung.


2
+1 vì đây là một câu trả lời chu đáo, nhưng tôi vẫn nghĩ rằng sẽ tốt hơn khi có một loạt các mẫu được sắp xếp tuyến tính với một thư viện thực hiện từng bước và trong khi tôi nghĩ rằng bạn có thể đúng về thái độ đối với XSL (Tôi Dựa vào trại nghĩ rằng đó là một vấn đề định dạng mặc dù phong cách đệ quy thừa nhận cần một chút quen thuộc), tôi cá rằng một số vấn đề có thể là quán tính khi cần phát triển một ngôn ngữ như vậy để sử dụng nó (ví dụ: tôi đang tìm ngay cả bản thân JSONPath cũng cần một vài cải tiến).
Brett Zamir

SpahQL dường như không có các mẫu riêng, vì vậy dường như không có đối thủ nào thực sự sử dụng JavaScript hoặc JSON thuần cho mã mẫu (cùng với các cấu trúc dữ liệu) mặc dù có các thư viện cho phép biểu thị HTML dưới dạng JSON / JS.
Brett Zamir

1
+1 mặc dù thực tế là có một cái gì đó về XSLT mà không có gì khác hoàn toàn có thể sao chép. JSON chắc chắn sẽ là một cú pháp khó hơn để viết một tương đương có thể sử dụng được.
dùng52889

7

Trong khi Jonathan chủ yếu nói về bản chất của XSLT như một ngôn ngữ trong câu trả lời của mình, tôi nghĩ có một góc độ khác để xem xét.

Mục đích của XSLT là chuyển đổi các tài liệu XML thành một số tài liệu khác (XML, HTML, SGML, PDF, v.v.). Theo cách này, XSLT thường được sử dụng, một cách hiệu quả, như một ngôn ngữ mẫu.

Có rất nhiều thư viện mẫu ngoài đó, ngay cả khi bạn tự giới hạn mình trong các thư viện JavaScript (mà bạn không cần, vì JS trong JSON chỉ đề cập đến nguồn gốc của ký hiệu và không nên dùng để ám chỉ JSON đó chỉ dành cho JavaScript). Công cụ chọn công cụ mẫu này đưa ra và chỉ ra sự đa dạng của các tùy chọn JS hiện có.

Nửa câu hỏi sau của bạn nói nhiều hơn về các ngôn ngữ truy vấn và phiên bản XML của các câu hỏi này sẽ là XPath (không phải XSLT). Như bạn đã lưu ý, có rất nhiều lựa chọn ở đó và tôi không có gì để thêm vào danh sách đó. Khu vực này tương đối mới, vì vậy tôi khuyên bạn nên chọn một và chỉ cần đi với nó.


Trong trường hợp có bất kỳ nghi ngờ nào, tôi nghĩ câu trả lời của Jonathan là tuyệt vời; Tôi chỉ muốn thêm một quan điểm thay thế.
Dancrumb

Đúng, điểm công bằng (và có lại: XPath tương đương với phần thứ hai), nhưng tôi rất thích xem JS XSL của tôi (gọi nó là JTLT) sử dụng JSONPath nâng cao chuyển đổi JSON sang ngôn ngữ khác (ví dụ: HTML là một ngôn ngữ chuỗi hoặc DOM).
Brett Zamir

Tôi có thư viện riêng của mình có tên Jamilih mà tôi thích để thể hiện HTML thô dưới dạng JS / JSON, nhưng tôi cần một cái gì đó tự nhiên và tôi hy vọng hấp dẫn cho 1) Mẫu và đường dẫn khớp 2) Các API lặp tương đương với xsl: application-samples và xsl: mẫu cuộc gọi (xsl: for-Each là hiển nhiên đối với JS, nhưng không phải là JSON). Đối với JS, tôi có thể sử dụng các hàm cho các mẫu và cho JSON (dựa trên Jamilih và các API lặp đó). Sẽ làm thế nào để nó đi ...
Brett Zamir

3

Dưới đây là một vài ví dụ về những gì bạn có thể làm với ( [jslt.min.js] ) nhỏ của tôi - JavaScript Biến đổi nhẹ:

https://jsfiddle.net/YSharpL Language / c7usrpsL/10

( [jslt.min.js] nặng ~ 3,1kb )

đó là, chỉ một chức năng,

function Per ( subject ) { ... }

... mà thực sự bắt chước mô hình xử lý của XSLT (1.0) .

(xem các hàm bên trong "biến đổi" và "mẫu", trong cơ thể của Per)

Vì vậy, về bản chất, nó chỉ đơn giản là tất cả được đưa vào một đĩa đơn function Per ( subject ) { ... }mà từ đó đánh giá nó về loại đối số duy nhất (cũng) của nó, để thực hiện, hoặc:

1) Chủ đề mảng

tạo nodeset / lọc / phẳng / nhóm / đặt hàng / etc , nếu đối tượng là một mảng, nơi nodeset kết quả (một mảng cũng) được mở rộng với, và bị ràng buộc với các phương pháp đặt tên cho phù hợp ( chỉ trả về mảng thể hiện của các cuộc gọi đến Per ( subjectArray )là mở rộng; tức là Array.prototype không được chạm tới)

tức là, Per :: Array --> Array

(các phương thức mở rộng của Mảng kết quả có các tên tự giải thích, chẳng hạn như groupBy, orderBy, flattenBy, v.v. - xem cách sử dụng trong các ví dụ)

2) Chủ đề chuỗi

nội suy chuỗi , nếu chủ đề là một chuỗi

("Per" sau đó trả về một đối tượng bằng một phương thức map ( source ), được liên kết với chuỗi mẫu chủ đề )

tức là Per :: String --> {map :: ( AnyValue --> String )}

ví dụ,

Per("Hi honey, my name is {last}. {first}, {last}.").map({ "first": "James", "last": "Bond" })

sản lượng:

"Hi honey, my name is Bond. James, Bond."

trong khi một trong hai

Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ])

hoặc là

Per("Those '{*}' are our 10 digits.").map(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

năng suất như nhau:

"Those '0123456789' are our 10 digits."

nhưng chỉ

Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], ", ")

sản lượng

"Those '0, 1, 2, 3, 4, 5, 6, 7, 8, 9' are our 10 digits."

3) Chuyển đổi chủ đề

Phép biến đổi trông giống XSLT , nếu đối tượng là hàm băm với thành viên "$" được quy định theo quy ước, cung cấp mảng quy tắc viết lại (và giống như trong (2), "Per" sau đó trả về một đối tượng có phương thức được map ( source )liên kết với chủ thể biến đổi - nơi

"ruleName" trong Per ( subjectTransform [ , ruleName ])là tùy chọn và cung cấp chức năng tương tự như <xsl: call-template name = "templateName"> ...)

tức là Per :: ( Transform [, ruleName :: String ]) -->{map :: ( AnyValue --> AnyValue )}

với

Transform :: {$ :: Mảng quy tắc viết lại [rw.r.] }

( [rw.r.] cặp chức năng vị ngữ và mẫu)

ví dụ: được đưa ra (... một ví dụ khác)

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

var a_transform = { $: [
//...
  [ [ Member ], // (alike <xsl:template match="...">...)
      function(member) {
        return {
          li: Per("{first} {last}").map(member) +
              " " +
              Per(this).map({ gender: member.sex })
        };
      }
  ],

  [ [ function(info) { return info.gender; } ], // (alike <xsl:template match="...">...)
      function(info) { return Per("(gender: {gender})").map(info); }
  ],

  [ [ "betterGenderString" ], // (alike <xsl:template name="betterGenderString">...)
      function(info) {
        info.pronoun = info.pronoun || "his/her";
        return Per("({pronoun} gender is {gender})").map(info);
      }
  ]
//...
] };

sau đó

Per(a_transform).map({ "first": "John", "last": "Smith", "sex": "Male" })

sản lượng:

{ "li": "John Smith (gender: Male)" }

trong khi ... (rất giống nhau <xsl:call-template name="betterGenderString">...)

"James Bond... " +
Per(a_transform, "betterGenderString").map({ "pronoun": "his", "gender": "Male" })

sản lượng:

"James Bond... (his gender is Male)"

"Someone... " +
Per(a_transform, "betterGenderString").map({ "gender": "Male or Female" })

sản lượng:

"Someone... (his/her gender is Male or Female)"

4) Mặt khác

chức năng nhận dạng , trong tất cả các trường hợp khác

tức là Per :: T --> T

(tức là Per === function ( value ) { return value ; })

Ghi chú

trong (3) ở trên, "cái này" của JavaScript trong phần thân của hàm khuôn mẫu do đó bị ràng buộc với Biến đổi bộ chứa / chủ sở hữu và bộ quy tắc của nó (như được định nghĩa bởi mảng $: [...]) - do đó, làm cho biểu thức "Per (this)", trong bối cảnh đó, tương đương về mặt chức năng với XSLT

<xsl:apply-templates select="..."/>

'HTH,


1
Điều đó thật tuyệt.
Robert Harvey

@RobertHarvey: bên cạnh sự căng thẳng của phần 5.1 và bản thân tôi đã nhận thấy từ lâu, cuối cùng tôi cũng bị thu hút và truyền cảm hứng bởi nhận xét hấp dẫn của Evan Lenz "XSLT đơn giản hơn bạn nghĩ!", Tại http: // www. lenzconsulting.com/how-xslt-works - và vì vậy tôi quyết định đưa ra một cú đánh để xác minh tuyên bố đó (nếu chỉ vì tò mò) bằng ngôn ngữ rất dễ uốn là JavaScript.
YSharp

Cảm ơn bạn rất nhiều vì đã trả lời chi tiết của bạn. Tôi đang bận rộn với một số thứ khác (bao gồm cả tương đương XSLT của riêng tôi), nhưng tôi có ý định quay lại vấn đề này để có cái nhìn cẩn thận hơn.
Brett Zamir

3

Gần đây tôi đã tạo ra một thư viện, json-Transforms , chính xác cho mục đích này:

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

Nó sử dụng một sự kết hợp của JSPath , DSL được mô hình hóa trên XPath và một cách tiếp cận khớp mẫu đệ quy, lấy cảm hứng trực tiếp từ XSLT.

Đây là một ví dụ nhanh. Cho đối tượng JSON sau:

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 }
  ]
};

Đây là một sự chuyển đổi:

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);

Đầu ra nào sau đây:

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

Biến đổi này bao gồm ba quy tắc. Chiếc đầu tiên phù hợp với bất kỳ chiếc ô tô nào được sản xuất bởi Honda, phát ra một vật thể có Hondatài sản, sau đó khớp theo cách đệ quy. Quy tắc thứ hai khớp với bất kỳ đối tượng nào có thuộc makertính, xuất ra các thuộc tính modelyear. Cuối cùng là biến đổi danh tính phù hợp đệ quy.


+1 và cảm ơn về thông tin. Tôi hy vọng sẽ hoàn thành github.com/brettz9/jtlt của riêng mình vào một lúc nào đó, nhưng thật hữu ích khi có nhiều triển khai để so sánh.
Brett Zamir

-1

Tôi không nghĩ bạn sẽ có được một biến thể JSON cho JSON mỗi lần. Tồn tại một số công cụ tạo khuôn mẫu như Python's Jinja2, JavaScripts Nunjucks, Groovy MarkupTemplateEngine và nhiều công cụ khác rất phù hợp với những gì bạn muốn. .NET có hỗ trợ tuần tự hóa / khử tuần tự T4 và JSON để bạn cũng có.

Vì dữ liệu JSON được tối ưu hóa về cơ bản sẽ là một cấu trúc từ điển hoặc bản đồ, điều đó sẽ vượt qua công cụ tạo khuôn mẫu của bạn và bạn sẽ lặp lại các nút mong muốn ở đó. Dữ liệu JSON sau đó được chuyển đổi theo mẫu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.