2017-09-26 50 views
0

我從Apex代碼中的REST服務響應中獲取YAML字符串,我尋找一些類似的方法來解析它並將其轉換爲Salesforce對象的集合。如何解析Salesforce Apex中的YAML對象

舉例來說,我得到這樣的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 

,我想將它轉化成書的對象名單。當我使用JSON工作時,我使用了JSON class,它提供了反序列化功能,並且我想知道,Salesforce是否爲YAML處理提供了類似的功能?

+1

他們沒有。你必須手動解析。 –

回答

1

注意:這是複製/粘貼從我給same question on the Salesforce SE site的答案。

不,在撰寫本文時(API v41.0),Salesforce沒有任何內置功能來創建或解析YAML。這意味着您需要構建自己的(或者將其他語言(如Java)中的現有語言修改爲Apex)。

如果您不是在尋找一個通用的解析器(可以處理任何有效的YAML的東西),而且您也不希望接收到的數據格式發生變化,那麼編寫一個特定於域的解析器應該沒有太多的工作。

當我發現自己在使用XML時,我喜歡將傳入的模式分解爲單獨的apex類並將解析方法構建到每個類中。這樣做可以保持解析器的可管理性。 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]);