1. 程式人生 > 其它 >django_請求與響應

django_請求與響應

語法

  • YAML 使用可列印的 Unicode 字元,可使用 UTF-8 或 UTF-16。

  • 使用空白字元為檔案縮排來表示結構;不過不能使用跳格字元 (TAB)。

  • 註解由井字號( # )開始,可以出現在一行中的任何位置,而且範圍只有一行(也就是一般所謂的單行註解)

  • 每個清單成員以單行表示,並用短槓 + 空白( - )起始。或使用方括號( [ ] ),並用逗號 + 空白( , )分開成員。

  • 每個散列表的成員用冒號 + 空白( : )分開鍵值和內容。或使用大括號( { } ),並用逗號 + 空白( , )分開。

  • 散列表的鍵值可以用問號 ( ? ) 起始,用來明確的表示多個詞彙組成的鍵值。

  • 字串平常並不使用引號,但必要的時候可以用雙引號 ( " ) 或單引號 ( ' ) 框住。

  • 使用雙引號表示字串時,可用倒斜線( \ )開始的轉義字元(這跟 C 語言類似)表示特殊字元。

  • 區塊的字串用縮排和修飾符(非必要)來和其他資料分隔,有新行保留(preserve)(使用符號 | )或新行摺疊(flod)(使用符號 > )兩種方式。

  • 在單一檔案中,可用連續三個連字號(---)區分多個檔案。

  • 另外,還有選擇性的連續三個點號( ... )用來表示檔案結尾。

  • 重複的內容可使從參考標記星號 ( * ) 複製到錨點標記( & )。

  • 指定格式可以使用兩個驚歎號 ( !! ),後面接上名稱。

  • 檔案中的單一檔案可以使用指導指令,使用方法是百分比符號 ( % )。有兩個指導指令在 YAML1.1 版中被定義:

    • % YAML 指導指令,用來識別檔案的 YAML 版本。
    • % TAG 指導指令,被用在 URI 的字首標記。這個方法在標記節點的型別時相當有用。
  • YAML 在使用逗號及冒號時,後面都必須接一個空白字元,所以可以在字串或數值中自由加入分隔符號(例如:5,280 或 http://www.wikipedia.org)而不需要使用引號。

  • 另外還有兩個特殊符號在 YAML 中被保留,有可能在未來的版本被使用 --( @ )和( ` )

libyaml庫解析YAML檔案

libyaml是一個用於解析YAML檔案的C語言庫,可以從包管理器中獲得。要使用它需要包含<yaml.h>檔案並且在gcc中加上鍊接器標誌 -lyaml,詳細資訊檢視標頭檔案/usr/include/yaml.h

示例文件:

# config/public.yaml

title   : Finex 2011
img_url : /finex/html/img/
css_url : /finex/html/style/
js_url  : /finex/html/js/

template_dir: html/templ/

default_act : idx    # used for invalid/missing act=

pages:
  - act   : idx
    title : Welcome
    html  : public/welcome.phtml
  - act   : reg
    title : Register
    html  : public/register.phtml
  - act   : log
    title : Log in
    html  : public/login.phtml
  - act   : out
    title : Log out
    html  : public/logout.phtml

yaml_parser_t

libyaml使用的主要物件就是解析器本身,這是一個yaml_parser_t型別的物件。它必須手動分配(通常在棧上)並且使用以下函式初始化和釋放:

int yaml_parser_initialize(yaml_parser_t *)
void yaml_parser_delete(yaml_parser_t *)

開啟一個特定的檔案,使用函式:(還有一些函式用於從字串或通用讀處理程式中讀取輸入,並且設定輸入檔案的編碼方式,在這裡不做討論)

void yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file)

基於Token和基於Event的解析

使用libyaml解析一個YAML文件有兩種方式:token-basedevent-based。概念上,最簡單的方式是基於token,通過使用以下函式:

int yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token)
void yaml_token_delete(yaml_token_t *token)

我們能從YAML文件中依次獲得每一個token,完整的yaml_token_t結構在<yaml.h>檔案中。但就我們的目的而言,僅需要.type.data.scalar.value兩個欄位,它能告訴我們token的型別以及資料(如果型別是YAML_SCALAR_TOKEN)

以下程式碼是使用示例:

#include <stdio.h>
#include <yaml.h>

int main(void)
{
  FILE *fh = fopen("config/public.yaml", "r");
  yaml_parser_t parser;
  yaml_token_t  token;   /* new variable */

  /* Initialize parser */
  if(!yaml_parser_initialize(&parser))
    fputs("Failed to initialize parser!\n", stderr);
  if(fh == NULL)
    fputs("Failed to open file!\n", stderr);

  /* Set input file */
  yaml_parser_set_input_file(&parser, fh);

  /* BEGIN new code */
  do {
    yaml_parser_scan(&parser, &token);
    switch(token.type)
    {
    /* Stream start/end */
    case YAML_STREAM_START_TOKEN: puts("STREAM START"); break;
    case YAML_STREAM_END_TOKEN:   puts("STREAM END");   break;
    /* Token types (read before actual token) */
    case YAML_KEY_TOKEN:   printf("(Key token)   "); break;
    case YAML_VALUE_TOKEN: printf("(Value token) "); break;
    /* Block delimeters */
    case YAML_BLOCK_SEQUENCE_START_TOKEN: puts("<b>Start Block (Sequence)</b>"); break;
    case YAML_BLOCK_ENTRY_TOKEN:          puts("<b>Start Block (Entry)</b>");    break;
    case YAML_BLOCK_END_TOKEN:            puts("<b>End block</b>");              break;
    /* Data */
    case YAML_BLOCK_MAPPING_START_TOKEN:  puts("[Block mapping]");            break;
    case YAML_SCALAR_TOKEN:  printf("scalar %s \n", token.data.scalar.value); break;
    /* Others */
    default:
      printf("Got token of type %d\n", token.type);
    }
    if(token.type != YAML_STREAM_END_TOKEN)
      yaml_token_delete(&token);
  } while(token.type != YAML_STREAM_END_TOKEN);
  yaml_token_delete(&token);
  /* END new code */

  /* Cleanup */
  yaml_parser_delete(&parser);
  fclose(fh);
  return 0;
}

對於簡單的文件,顯然基於token的解析是有意義的。然而,更合理的範例是基於event解析。這是通過類似的函式實現的

int yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event)
void yaml_event_delete(yaml_event_t *event)

使用這些函式實現的程式碼及輸出如下所示:

#include <stdio.h>
#include <yaml.h>

int main(void)
{
  FILE *fh = fopen("config/public.yaml", "r");
  yaml_parser_t parser;
  yaml_event_t  event;   /* New variable */

  /* Initialize parser */
  if(!yaml_parser_initialize(&parser))
    fputs("Failed to initialize parser!\n", stderr);
  if(fh == NULL)
    fputs("Failed to open file!\n", stderr);

  /* Set input file */
  yaml_parser_set_input_file(&parser, fh);

  /* START new code */
  do {
    if (!yaml_parser_parse(&parser, &event)) {
       printf("Parser error %d\n", parser.error);
       exit(EXIT_FAILURE);
    }

    switch(event.type)
    { 
    case YAML_NO_EVENT: puts("No event!"); break;
    /* Stream start/end */
    case YAML_STREAM_START_EVENT: puts("STREAM START"); break;
    case YAML_STREAM_END_EVENT:   puts("STREAM END");   break;
    /* Block delimeters */
    case YAML_DOCUMENT_START_EVENT: puts("<b>Start Document</b>"); break;
    case YAML_DOCUMENT_END_EVENT:   puts("<b>End Document</b>");   break;
    case YAML_SEQUENCE_START_EVENT: puts("<b>Start Sequence</b>"); break;
    case YAML_SEQUENCE_END_EVENT:   puts("<b>End Sequence</b>");   break;
    case YAML_MAPPING_START_EVENT:  puts("<b>Start Mapping</b>");  break;
    case YAML_MAPPING_END_EVENT:    puts("<b>End Mapping</b>");    break;
    /* Data */
    case YAML_ALIAS_EVENT:  printf("Got alias (anchor %s)\n", event.data.alias.anchor); break;
    case YAML_SCALAR_EVENT: printf("Got scalar (value %s)\n", event.data.scalar.value); break;
    }
    if(event.type != YAML_STREAM_END_EVENT)
      yaml_event_delete(&event);
  } while(event.type != YAML_STREAM_END_EVENT);
  yaml_event_delete(&event);
  /* END new code */

  /* Cleanup */
  yaml_parser_delete(&parser);
  fclose(fh);
  return 0;
}
STREAM START 
Start Document 
  Start Mapping 
    Got scalar (value title) 
    Got scalar (value Finex 2011) 
    Got scalar (value img_url) 
    Got scalar (value /finex/html/img/) 
    Got scalar (value css_url) 
    Got scalar (value /finex/html/style/) 
    Got scalar (value js_url) 
    Got scalar (value /finex/html/js/) 
    Got scalar (value template_dir) 
    Got scalar (value html/templ/) 
    Got scalar (value pages) 
    Start Sequence 
      Start Mapping 
        Got scalar (value act) 
        Got scalar (value idx) 
        Got scalar (value title) 
        Got scalar (value Welcome) 
        Got scalar (value html) 
        Got scalar (value public/welcome.phtml) 
      End Mapping 
      Start Mapping 
        Got scalar (value act) 
        Got scalar (value reg) 
        Got scalar (value title) 
        Got scalar (value Register) 
        Got scalar (value html) 
        Got scalar (value public/register.phtml) 
      End Mapping 
      Start Mapping 
        Got scalar (value act) 
        Got scalar (value log) 
        Got scalar (value title) 
        Got scalar (value Log in) 
        Got scalar (value html) 
        Got scalar (value public/login.phtml) 
      End Mapping 
      Start Mapping 
        Got scalar (value act) 
        Got scalar (value out) 
        Got scalar (value title) 
        Got scalar (value Log out) 
        Got scalar (value html) 
        Got scalar (value public/logout.phtml) 
      End Mapping 
    End Sequence 
  End Mapping 
End Document 
STREAM END 

關於這個有兩件主要的事情要注意。第一,輸出的結構更好,通用的End Block令牌現在是具體的事件。第二,程式碼更簡單,不僅如此,switch分支有每一種事件型別,在基於token的程式碼中,switch分支的宣告是不完整的,還應該包含許多其他的token,並且大多數我都不理解。

而且,基於event的程式碼更適合面向物件程式設計,當在其他語言中使用libyaml時你可能會看到

基於Document解析

實際上還有第三種方式解析YAML,基於以下函式:

int yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document)
void yaml_document_delete(yaml_document_t *document)

它允許你載入一個單獨的文件到結構中,並且使用各種yaml_document_*函式。這是很有用的,因為YAML文件可能分散在多個檔案中,或者單檔案包含許多YAML文件。

YAML的基本元件

YAML 提供縮排/區塊以及內建(inline)兩種格式,來表示清單和散列表。以下展示幾種 YAML 的基本原件。

清單(陣列)

--- # 最喜愛的電影  
- Casablanca  
- North by Northwest  
- Notorious 

另外還有一種內建格式(inline format)可以選擇──用方括號圍住,並用逗號 + 空白區隔(類似 JSON 的語法)

 --- # 購物清單  
 [milk, pumpkin pie, eggs, juice]

散列表

鍵值和資料由冒號及空白字元分開。區塊形式(常用於YAML資料文件中)使用縮排和換行符分隔 key:value 對。內建形式(常用於YAML資料流中)在大括號中使用逗號+空白字元分隔 key:value 對。

 --- # 區塊形式
   name: John Smith
   age: 33
 --- # 內建形式
 {name: John Smith, age: 33}

層次結構化的元素

清單中使用散列表

- {name: John Smith, age: 33}
- name: Mary Smith
  age: 27

散列表中使用清單

men: [John Smith, Bill Jones]
women:
  - Mary Smith
  - Susan Williams

YAML的高階元件

YAML最常被提到的特色有兩個:關係樹和資料形態

樹狀結構之間的互動引用

資料合併和參考

為了維持檔案的簡潔,並避免資料輸入的錯誤,YAML 提供了結點參考(*)和雜湊合併(<<)參考到其他結點標籤的錨點標記(&)。參考會將樹狀結構加入錨點標記的內容,並可以在所有資料結構中運作,合併只有散列表可以使用,可以將鍵值自錨點標記複製到指定的散列表中。

當資料被 instantiate 合併和參考會被剖析器自動展開。

#眼部雷射手術之標準程式
---
- step:  &id001                  # 定義錨點標籤 &id001
    instrument:      Lasik 2000
    pulseEnergy:     5.4
    pulseDuration:   12
    repetition:      1000
    spotSize:        1mm

- step:
     <<: *id001                  # 合併鍵值:使用在錨點標籤定義的內容
     spotSize:       2mm         # 覆寫"spotSize"鍵值

- step:
     <<: *id001                  # 合併鍵值:使用在錨點標籤定義的內容
     pulseEnergy:    500.0       # 覆寫鍵值
     alert: >                    # 加入其他鍵值
           warn patient of 
           audible pop

資料形態

參考文件:https://www.jianshu.com/p/a65e692edd5a