如何在 Salesforce Apex 中解析 YAML 对象
How to parse YAML object in Salesforce Apex
我从 Apex 代码中的 REST 服务响应中得到一个 YAML 字符串,我寻找一些类似的方法来解析它并将其转换为 Salesforce 对象的集合。
例如,我得到这样的 YAML 作为字符串:
---
item:
-
title: A Grief Observed
author: C. S. Lewis
author_by_last: Lewis, C. S.
isbn: "0060652381"
publisher: ZOND
on_hand: "5"
in_pub_date: 2001-01-01
-
title: "Grief Sanctified: From Sorrow to Eternal Hope: Including Richard Baxter's Timeles"
author: J. I. Packer
author_by_last: Packer, J. I.
isbn: "1581344406"
publisher: CROSS
on_hand: "5"
in_pub_date: 2002-09-01
我想将其转换为 Book 对象列表。当我使用 JSON 时,我使用了 JSON class,它提供了反序列化功能,我想知道,Salesforce 是否为 YAML 处理提供了类似的东西?
注意:这是 copy/pasted 我在 same question on the Salesforce SE site 上给出的答案。
不,在撰写本文时 (API v41.0),Salesforce 没有任何内置功能来创建或解析 YAML。这意味着您需要构建自己的(或将现有语言从另一种语言改编成 Apex,例如 Java)。
如果您不是在寻找通用解析器(可以处理任何有效 YAML 的东西)并且您不希望您接收的数据格式发生变化,请编写一个特定于域的解析器不应该做太多工作。
当我发现自己在使用 XML 时,我喜欢将传入的模式分解为单独的顶点 类 并在每个顶点中构建解析方法。这样做可以使解析器易于管理。 YAML 也可以采用类似的方法。
// Yes, the need for this BookCollection object is debatable (it's mainly just storing
// a List).
// Encapsulating the parsing makes it worth being made into a class (in my mind).
public class BookCollection{
// The class variables for each level mimic the data stored on each level
// of the schema of your incoming data.
// This will become more apparent later.
public List<Book> item;
public BookCollection(String input){
item = new List<Book>();
// At this level, all we're concerned about is finding the individual books.
// Once we find a book, we pass it down to the next level of parsing (and
// add the result to our list)
// YAML uses whitespace to denote structure, so we need to take that into
// account when splitting.
// The regex here looks for two spaces, a hyphen, one space, a newline.
// Everything after that (up to the next ' - \n' or EOF) is book data.
// String.split() will return 'item:' as the first part.
// That isn't part of the data for a book, so we'll want to remove that.
List<String> bookStringsList = input.split(' - \n');
bookStringsList.remove(0);
for(String bookString :bookStringsList){
Book currentBook = new Book(bookString);
item.add(currentBook);
}
}
}
public class Book{
// Now it should be more apparent that we're mimicking the structure of the
// incoming data.
String title;
String author;
String author_by_last;
String isbn;
String publisher;
Integer on_hand;
Date in_pub_date;
public Book(String input){
// On this level of parsing, we have actual data to work with.
// Our job here is to find all of the key:value pairs, and cast them to
// their appropriate types.
for(String keyAndValue :input.split(' \n')){
String key, value;
List<String> kvSplit = keyAndValue.split(':');
key = kvSplit[0];
// Double quotes are likely to mess things up, so remove them.
value = kvSplit[1].replace('"', '');
// There's probably a more elegant way to handle this than a big 'ol
// if/else if chain...but this'll work
if(key == 'title'){
this.title = value;
} else if(key == 'author'){
this.author = value;
} else if(key == 'author_by_last'){
this.author_by_last = value;
} else if(key == 'isbn'){
this.isbn = value;
} else if(key == 'publisher'){
this.publisher = value;
} else if(key == 'on_hand'){
// String -> Integer is pretty easy, we can use Integer.valueOf()
this.on_hand = Integer.valueOf(value);
} else if(key == 'in_pub_date'){
// Dates are a bit tricky.
// Salesforce wants them in YYYY-MM-DDThh:mm:ssZ format, or the format
// used in your locale (for parse() or valueOf()).
// Given our data, it's easiest to simply generate a new date instance
List<String> dateParts = value.split('-');
this.in_pub_date = Date.newInstance(dateParts[0], dateParts[1], dateParts[2]);
}
}
}
}
使用这些 类 非常简单。但是,它确实需要一些额外的设置。
// Your YAML, from some source
String myYAML = blackBox.getData();
// Break up your YAML's documents before attempting to parse each one.
List<String> documents = myYAML.split('---\n');
// The first result string will likely always be empty, so we can remove that.
documents.remove(0);
// This is the simple case where we know we're only dealing with a single document.
// If you had multiple documents in a single YAML string, you would (hopefully)
// be able to tell which type of document you were working with (and you'd
// need additional logic to determine which parser class to send the data to).
BookCollection myBooks = new BookCollection(documents[0]);
我从 Apex 代码中的 REST 服务响应中得到一个 YAML 字符串,我寻找一些类似的方法来解析它并将其转换为 Salesforce 对象的集合。
例如,我得到这样的 YAML 作为字符串:
---
item:
-
title: A Grief Observed
author: C. S. Lewis
author_by_last: Lewis, C. S.
isbn: "0060652381"
publisher: ZOND
on_hand: "5"
in_pub_date: 2001-01-01
-
title: "Grief Sanctified: From Sorrow to Eternal Hope: Including Richard Baxter's Timeles"
author: J. I. Packer
author_by_last: Packer, J. I.
isbn: "1581344406"
publisher: CROSS
on_hand: "5"
in_pub_date: 2002-09-01
我想将其转换为 Book 对象列表。当我使用 JSON 时,我使用了 JSON class,它提供了反序列化功能,我想知道,Salesforce 是否为 YAML 处理提供了类似的东西?
注意:这是 copy/pasted 我在 same question on the Salesforce SE site 上给出的答案。
不,在撰写本文时 (API v41.0),Salesforce 没有任何内置功能来创建或解析 YAML。这意味着您需要构建自己的(或将现有语言从另一种语言改编成 Apex,例如 Java)。
如果您不是在寻找通用解析器(可以处理任何有效 YAML 的东西)并且您不希望您接收的数据格式发生变化,请编写一个特定于域的解析器不应该做太多工作。
当我发现自己在使用 XML 时,我喜欢将传入的模式分解为单独的顶点 类 并在每个顶点中构建解析方法。这样做可以使解析器易于管理。 YAML 也可以采用类似的方法。
// Yes, the need for this BookCollection object is debatable (it's mainly just storing
// a List).
// Encapsulating the parsing makes it worth being made into a class (in my mind).
public class BookCollection{
// The class variables for each level mimic the data stored on each level
// of the schema of your incoming data.
// This will become more apparent later.
public List<Book> item;
public BookCollection(String input){
item = new List<Book>();
// At this level, all we're concerned about is finding the individual books.
// Once we find a book, we pass it down to the next level of parsing (and
// add the result to our list)
// YAML uses whitespace to denote structure, so we need to take that into
// account when splitting.
// The regex here looks for two spaces, a hyphen, one space, a newline.
// Everything after that (up to the next ' - \n' or EOF) is book data.
// String.split() will return 'item:' as the first part.
// That isn't part of the data for a book, so we'll want to remove that.
List<String> bookStringsList = input.split(' - \n');
bookStringsList.remove(0);
for(String bookString :bookStringsList){
Book currentBook = new Book(bookString);
item.add(currentBook);
}
}
}
public class Book{
// Now it should be more apparent that we're mimicking the structure of the
// incoming data.
String title;
String author;
String author_by_last;
String isbn;
String publisher;
Integer on_hand;
Date in_pub_date;
public Book(String input){
// On this level of parsing, we have actual data to work with.
// Our job here is to find all of the key:value pairs, and cast them to
// their appropriate types.
for(String keyAndValue :input.split(' \n')){
String key, value;
List<String> kvSplit = keyAndValue.split(':');
key = kvSplit[0];
// Double quotes are likely to mess things up, so remove them.
value = kvSplit[1].replace('"', '');
// There's probably a more elegant way to handle this than a big 'ol
// if/else if chain...but this'll work
if(key == 'title'){
this.title = value;
} else if(key == 'author'){
this.author = value;
} else if(key == 'author_by_last'){
this.author_by_last = value;
} else if(key == 'isbn'){
this.isbn = value;
} else if(key == 'publisher'){
this.publisher = value;
} else if(key == 'on_hand'){
// String -> Integer is pretty easy, we can use Integer.valueOf()
this.on_hand = Integer.valueOf(value);
} else if(key == 'in_pub_date'){
// Dates are a bit tricky.
// Salesforce wants them in YYYY-MM-DDThh:mm:ssZ format, or the format
// used in your locale (for parse() or valueOf()).
// Given our data, it's easiest to simply generate a new date instance
List<String> dateParts = value.split('-');
this.in_pub_date = Date.newInstance(dateParts[0], dateParts[1], dateParts[2]);
}
}
}
}
使用这些 类 非常简单。但是,它确实需要一些额外的设置。
// Your YAML, from some source
String myYAML = blackBox.getData();
// Break up your YAML's documents before attempting to parse each one.
List<String> documents = myYAML.split('---\n');
// The first result string will likely always be empty, so we can remove that.
documents.remove(0);
// This is the simple case where we know we're only dealing with a single document.
// If you had multiple documents in a single YAML string, you would (hopefully)
// be able to tell which type of document you were working with (and you'd
// need additional logic to determine which parser class to send the data to).
BookCollection myBooks = new BookCollection(documents[0]);