XSLT เทียบเท่ากับ JSON


15

ฉันสนใจในการค้นหา (หรือหากจำเป็นต้องพัฒนา) เทียบเท่า XSLT สำหรับ JSON

เนื่องจากฉันไม่พบใด ๆ ฉันกำลังพิจารณาภาษาคิวรีที่เป็นไปได้ที่จะใช้สำหรับการจับคู่พา ธ JSON เพื่อใช้เทมเพลต (จาก JavaScript) เมื่อมีการจับคู่ (อาจแค่ตรวจสอบอาร์เรย์ของรูปแบบการจับคู่ตามลำดับและหยุดที่ แม่แบบแรกที่ตรงกับแม้ว่าอนุญาตให้เทียบเท่ากับ xsl: Apply-templates เพื่อให้แม่แบบไปสำหรับเด็ก)

ฉันรับรู้ถึง JSONPath, JSONQuery และ RQL เป็นภาษาคิวรี JSON (แม้ว่าฉันจะไม่ชัดเจนว่า RQL สนับสนุนเส้นทางสัมบูรณ์และเส้นทางสัมพัทธ์หรือไม่) ข้อเสนอแนะเกี่ยวกับปัจจัยที่ต้องพิจารณาและความได้เปรียบของแต่ละข้อต่อการใช้งานดังกล่าว


แค่คิดแบบจาวาสคริปต์และหนวด / แฮนด์บาร์อาจจะ? :)
Knerd

ขอบคุณ แต่ฉันกระตือรือร้นที่จะใช้วิธีมาตรฐาน (เช่นอย่างน้อยหนึ่งที่มีศักยภาพเนื่องจากการแสดงออกของเส้นทาง JSON ทั่วไปจะเป็นวิธีที่ได้รับการยอมรับโดยทั่วไปของการอ้างอิง JSON ซึ่งตรงข้ามกับบางไวยากรณ์ที่เฉพาะเจาะจงกับห้องสมุด)
Brett Zamir


1
ฉันพบสิ่งที่น่าสนใจเช่นนี้: json-template.googlecode.com/svn/trunk/doc/…
Robert Harvey

ฉันทำ Json -> XML -> XSLT -> Json มาก่อน - ใช้งานได้ดีแม้ว่าจะไม่ใช่โซลูชันที่มีประสิทธิภาพมากที่สุด
user2813274

คำตอบ:


27

XML: XSLT :: JSON: x xคืออะไร

คำตอบที่ง่ายที่สุดคือx = JavaScript แม้ว่าคุณจะสามารถทำเรื่องนี้ได้ แต่ก็รู้สึกไม่พอใจ แม้ว่า XSLT จะใช้เทคนิคทัวริงเสร็จสิ้นแต่ก็มีความสอดคล้องที่ไม่ดีระหว่างสไตล์การประกาศของ XSLT และสไตล์ที่มีความจำเป็นหรือการทำงานมากกว่าที่เห็นใน JavaScript

มีภาษาคิวรี JSON แบบสแตนด์อโลนสองสามภาษาเช่นJSONPath , JSONiqและRQLซึ่งอาจยืนอยู่ตรงกลางของ XML: XPath :: JSON: y (หรืออาจเป็น XQuery มากกว่า XPath) และทุกฐานข้อมูลเอกสาร JSON ที่มุ่งเน้นมีภาษาแบบสอบถาม JSON ที่เกี่ยวข้อง

แต่ความจริงก็คือแม้ว่าจะมีคู่แข่งเพียงเล็กน้อยสำหรับตำแหน่ง XSLT เต็มรูปแบบเช่นSpahQLแต่ก็ไม่ได้รับการยอมรับโดยทั่วไป JSON เทียบเท่ากับ XSLT ในวงกว้าง

ทำไม?

ด้วย JSON ทั้งหมดในโลกเหตุใดจึงไม่มีแอนะล็อกกับ XSLT (โดยตรงมากขึ้น) เนื่องจากนักพัฒนาหลายคนมองว่า XSLT เป็นการทดลองที่ล้มเหลว เครื่องมือค้นหาใด ๆ ที่จะนำไปสู่การเสนอราคาเช่น "XSLT คือความล้มเหลวในการเจ็บปวด" คนอื่น ๆ แย้งว่าถ้ามันมีรูปแบบที่ดีขึ้นมันจะเป็นที่นิยมมากขึ้น แต่ที่น่าสนใจใน XSLT ได้ลดลงโดยทั่วไปในช่วงหลายปี เครื่องมือหลายอย่างที่รองรับมันรองรับเฉพาะรุ่น 1.0ซึ่งเป็นข้อกำหนดของปี 1999 รายละเอียดอายุสิบห้าปี? มีข้อมูลจำเพาะ 2.0 รุ่นใหม่กว่านี้มากและหากผู้คนกระตือรือร้นเกี่ยวกับ XSLT ก็จะได้รับการสนับสนุน มันไม่ใช่

โดยและนักพัฒนาขนาดใหญ่เลือกที่จะประมวลผลและแปลงเอกสาร XML ด้วยโค้ดไม่ใช่เทมเพลตการแปลง ดังนั้นจึงไม่น่าแปลกใจที่เมื่อทำงานกับ JSON พวกเขาก็จะเลือกที่จะทำเช่นนั้นในภาษาของตัวเองแทนที่จะเพิ่มระบบการแปลง "ต่างชาติ" เพิ่มเติม


2
+1 เนื่องจากเป็นคำตอบที่รอบคอบ แต่ฉันก็ยังคิดว่ามันสะอาดกว่าที่จะมีเทมเพลตเรียงเป็นเส้นตรงพร้อมกับห้องสมุดที่กำลังก้าวผ่านและในขณะที่ฉันคิดว่าคุณน่าจะมีทัศนคติที่ดีต่อ XSL (ฉันต้องการ เอนเอียงไปที่ค่ายคิดว่ามันเป็นปัญหาการจัดรูปแบบแม้ว่าสไตล์การเรียกซ้ำต้องเป็นที่คุ้นเคยบางอย่าง) ฉันคิดว่าปัญหาบางอย่างอาจเป็นความเฉื่อยในการที่จะต้องพัฒนาภาษาดังกล่าวเพื่อใช้งาน (เช่นฉันกำลังหา แม้แต่ JSONPath เองก็ต้องการการปรับปรุงเล็กน้อย)
Brett Zamir

SpahQL ดูเหมือนจะไม่มีเทมเพลตของตัวเองดังนั้นจึงดูเหมือนว่ายังไม่มีคู่แข่งที่ใช้ JavaScript หรือ JSON บริสุทธิ์สำหรับรหัสเทมเพลต (พร้อมกับโครงสร้างข้อมูล) แม้ว่าจะมีไลบรารีที่อนุญาตให้แสดงออก HTML เป็น JSON / JS
Brett Zamir

1
+1 แม้ว่าข้อเท็จจริงที่ว่ามีบางอย่างเกี่ยวกับ XSLT ที่ไม่มีสิ่งใดที่จะจัดการทำซ้ำได้ JSON จะเป็นไวยากรณ์ที่ยากกว่าในการเขียนเทียบเท่าที่ใช้งานได้
user52889

7

ในขณะที่โจนาธานส่วนใหญ่พูดถึงธรรมชาติของ XSLT เป็นภาษาในคำตอบของเขาฉันคิดว่ามีอีกมุมที่ต้องพิจารณา

วัตถุประสงค์ของ XSLT คือการแปลงเอกสาร XML เป็นเอกสารอื่น ๆ (XML, HTML, SGML, PDF, ฯลฯ ) ด้วยวิธีนี้ XSLT มักถูกใช้อย่างมีประสิทธิภาพเป็นภาษาแม่แบบ

มีเทมเพลตไลบรารีมากมายมากมายแม้ว่าคุณจะ จำกัด ตัวเองกับไลบรารี JavaScript (ซึ่งคุณไม่จำเป็นต้องใช้เนื่องจาก JS ใน JSON จะอ้างถึงการสร้างสัญลักษณ์เท่านั้นและไม่ควรใช้เพื่อบอกเป็นนัยว่า JSON สำหรับ JavaScript เท่านั้น) ตัวเลือกเอ็นจินเทมเพลตนี้ให้และบ่งบอกถึงความหลากหลายของตัวเลือก JS ที่มีอยู่

คำถามครึ่งหลังของคุณพูดถึงเพิ่มเติมเกี่ยวกับภาษาของแบบสอบถามและเวอร์ชัน XML ของเหล่านี้จะเป็น XPath (ไม่ใช่ XSLT) ดังที่คุณจดบันทึกมีตัวเลือกมากมายและฉันไม่ต้องการเพิ่มสิ่งใดลงในรายการ บริเวณนี้ค่อนข้างใหม่ดังนั้นฉันขอแนะนำให้คุณเลือกหนึ่งอันและไปกับมัน


ในกรณีที่มีข้อสงสัยฉันคิดว่าคำตอบของโจนาธานดีมาก ฉันแค่ต้องการเพิ่มมุมมองทางเลือก
Dancrumb

ใช่คะแนนที่เป็นธรรม (และใช่อีกครั้ง: XPath นั้นเทียบเท่ากับส่วนที่สอง) แต่ฉันสนใจที่จะเห็น JS XSL ของฉัน (เรียกว่า JTLT) ใช้ประโยชน์จาก JSONPath ที่ได้รับการปรับปรุงให้เปลี่ยน JSON เป็นภาษาอื่นด้วยเช่นกัน สตริงหรือ DOM)
Brett Zamir

ฉันมีห้องสมุดของตัวเองที่ชื่อว่า Jamilih ซึ่งฉันชอบที่จะแสดง HTML ดิบเป็น JS / JSON แต่ฉันต้องการบางสิ่งบางอย่างที่เป็นธรรมชาติและฉันหวังว่าลวงตาสำหรับ 1) เทมเพลตและพา ธ ที่ตรงกัน 2) ซ้ำ APIs เทียบเท่า xsl: Apply-templates call-template (xsl: for-each นั้นชัดเจนสำหรับ JS แต่ไม่ใช่ JSON) สำหรับ JS ฉันสามารถใช้ฟังก์ชั่นสำหรับเทมเพลตและสำหรับ JSON (อิง Jamilih และ API ที่วนซ้ำเหล่านั้น) พินัยกรรม ee ว่ามันไป ...
เบร็ท Zamir

3

นี่คือตัวอย่างเล็ก ๆ น้อย ๆ ของสิ่งที่คุณสามารถทำได้กับ ( jslt.min.js ) ขนาดเล็กของฉันJSLT - JavaScript Lightweight Transforms:

https://jsfiddle.net/YSharpLanguage/c7usrpsL/10

( [jslt.min.js]น้ำหนัก ~ 3.1kb ย่อขนาด )

นั่นคือเพียงฟังก์ชั่นเดียว

function Per ( subject ) { ... }

... ซึ่งอันที่จริงเลียนแบบXSLT (1.0) 's รูปแบบการประมวลผล

(เปรียบเทียบฟังก์ชันภายในของ "การแปลง" และ "แม่แบบ" ในเนื้อหาของ Per)

ดังนั้นในสาระสำคัญมันเป็นเพียงการอบเข้าสู่ซิงเกิ้ลเท่านั้นfunction Per ( subject ) { ... }ซึ่งจะทำการประเมินในรูปแบบของอาร์กิวเมนต์ที่ไม่ซ้ำกัน (เช่น) เพื่อนำไปใช้:

1) เรื่องของอาร์เรย์

สร้าง nodeset / กรอง / แฟบ / การจัดกลุ่ม / สั่งซื้อ / etcถ้าเรื่องเป็นอาร์เรย์ที่ nodeset ส่งผล (เป็นอาร์เรย์เช่นกัน) จะขยายออกไปด้วยและผูกพันกับวิธีการตั้งชื่อตาม ( เพียงกลับอาร์เรย์ตัวอย่างของการเรียกร้องให้Per ( subjectArray )มี Extended; คือ Array.prototype ถูกปล่อยไว้โดยไม่ถูกแตะต้อง)

เช่นต่อ :: Array --> Array

( เมธอดส่วนขยายของArray ที่ได้นั้นมีชื่อที่อธิบายตนเองเช่น groupBy, orderBy, flattenBy ฯลฯ - cf. การใช้งานในตัวอย่าง)

2) หัวเรื่องของสตริง

การแก้ไขสตริงหากหัวเรื่องเป็นสตริง

("ต่อ" แล้วส่งคืนวัตถุที่มีวิธีการmap ( source )ซึ่งถูกผูกไว้กับสตริงแม่แบบเรื่อง)

ie, Per :: String --> {map :: ( AnyValue --> String )}

เช่น,

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

อัตราผลตอบแทน:

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

ในขณะที่ทั้งสองอย่าง

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

หรือ

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

อัตราผลตอบแทนเดียวกัน:

"Those '0123456789' are our 10 digits."

แต่เท่านั้น

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

อัตราผลตอบแทน

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

3) แปลงวิชา

XSLT การเปลี่ยนแปลงรูปลักษณ์เหมือนกันถ้าเรื่องเป็นกัญชากับอัตภาพที่กำหนดไว้ "$" สมาชิกให้อาร์เรย์ของการเขียนกฎ (และเช่นเดียวกับใน (2), "ต่อ" แล้วส่งกลับวัตถุที่มีวิธีการmap ( source )ที่ถูกผูกไว้กับเรื่อง แปลง - ที่ไหน

"ruleName" in Per ( subjectTransform [ , ruleName ])เป็นทางเลือกและมีฟังก์ชันการทำงานที่คล้ายกับ <xsl: call-template name = "templateName"> ... )

เช่นต่อ :: ( เปลี่ยน [, ruleName :: String ]) -->{map :: ( AnyValue --> AnyValue )}

กับ

แปลง :: {$ :: อาร์เรย์ของกฎการเขียนใหม่[rw.r. ] }

( [rw.r. ] คู่ของเพรดิเคตและเทมเพลต)

เช่นได้รับ (... อีกตัวอย่างที่วางแผนไว้)

// (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);
      }
  ]
//...
] };

แล้วก็

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

อัตราผลตอบแทน:

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

ในขณะที่ ... (เหมือนกันมาก<xsl:call-template name="betterGenderString">...)

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

อัตราผลตอบแทน:

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

และ

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

อัตราผลตอบแทน:

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

4) มิฉะนั้น

ฟังก์ชั่นตัวตนในกรณีอื่น ๆ ทั้งหมด

เช่นต่อ :: T --> T

(เช่นPer === function ( value ) { return value ; })

บันทึก

ใน (3) ด้านบน JavaScript ของ "นี่" ในส่วนของฟังก์ชันเทมเพลตจึงถูกผูกไว้กับการแปลงคอนเทนเนอร์ / เจ้าของและชุดของกฎ (ตามที่กำหนดโดยอาร์เรย์ $: [... ]) - ดังนั้น ทำให้นิพจน์ "Per (this)" ในบริบทนั้นเทียบเท่ากับ XSLT ของ functionally

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

'HTH,


1
มันค่อนข้างเท่ห์
Robert Harvey

@ RobertHarvey: นอกเหนือจากความยากลำบากของหัวข้อ 5.1ในและของตัวเองที่ฉันสังเกตเห็นมานานแล้วในที่สุดฉันก็รู้สึกทึ่งและได้รับแรงบันดาลใจจากคำพูดติดหูของ Evan Lenz "XSLT นั้นง่ายกว่าที่คุณคิด!" ที่http: // www lenzconsulting.com/how-xslt-works - และดังนั้นฉันจึงตัดสินใจที่จะตรวจสอบการอ้างสิทธิ์นั้น (ถ้าออกจากความอยากรู้) ในภาษาที่อ่อนไหวมากนั่นคือ JavaScript
YSharp

ขอบคุณมากสำหรับการตอบกลับอย่างละเอียด ฉันกำลังยุ่งกับสิ่งอื่น ๆ (รวมถึง XSLT ที่เทียบเท่าของฉันเอง) แต่ฉันตั้งใจจะกลับไปที่สิ่งนี้เพื่อดูอย่างระมัดระวังมากขึ้น
Brett Zamir

3

ฉันเพิ่งสร้างห้องสมุดjson-transformsเพื่อจุดประสงค์นี้:

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

มันใช้การรวมกันของJSPath , DSL สร้างแบบจำลองบน XPath และวิธีการจับคู่รูปแบบซ้ำ recursive แรงบันดาลใจโดยตรงจาก 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คุณสมบัติแล้วจับคู่ซ้ำ กฎข้อที่สองจับคู่วัตถุใด ๆ กับmakerคุณสมบัติส่งออกmodelและyearคุณสมบัติ สุดท้ายคือการแปลงตัวตนที่ตรงกันซ้ำ


+1 และขอบคุณสำหรับข้อมูล ฉันหวังว่าจะทำให้github.com/brettz9/jtltของฉันเสร็จสมบูรณ์ในบางจุด แต่มันมีประโยชน์ที่จะมีการนำไปใช้งานเพิ่มเติมเพื่อเปรียบเทียบ
Brett Zamir

-1

ฉันไม่คิดว่าคุณจะได้รับตัวแปร JSON สำหรับ JSON ต่อ se มีเครื่องมือสร้างเท็มเพลตหลายอย่างเช่น Jinja2 ของ Python, JavaScripts Nunjucks, Groovy MarkupTemplateEngine และอื่น ๆ อีกมากมายที่ควรจะเหมาะสมกับสิ่งที่คุณต้องการ .NET มีการสนับสนุนการทำให้เป็นอนุกรม / deserialization T4 และ JSON เพื่อให้คุณมีเช่นกัน

เนื่องจากข้อมูล JSON ที่มีการเปลี่ยนแปลงจะเป็นโครงสร้างพจนานุกรมหรือแผนที่ซึ่งโดยทั่วไปจะผ่านเครื่องมือสร้างเทมเพลทของคุณและคุณจะทำซ้ำโหนดที่ต้องการ จากนั้นข้อมูล JSON จะถูกแปลงโดยเทมเพลต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.