Skip to content

yaml ​

原文: https://finproducts.atlassian.net/wiki/spaces/JIDD3/pages/34793947336/FIN+5.3.1+yaml 中文整理基于 FIN 5.3.1

导读: Fantom 的 YAML 解析器

以下为 API 参考,保留英文以便对照源码;目录已列出(英文标题便于检索);概述已尽量中译。


目录(导读) ​

  • classes
  • docs
  • YAML
    • Reading YAML documents
    • Writing YAML documents
    • Schemas
  • Slot Details
    • each
    • get
    • make
    • val
    • decode
    • equals
    • hash
    • loc
    • tag
    • toStr
    • write
    • makeFile
    • parse
    • core
    • encode
    • failsafe
    • json

API 正文(英文) ​

YAML ​

This pod provides the means for parsing YAML files into native Fantom objects, as well as transforming Fantom objects back into YAML text. For information about YAML, see https://yaml.org/.

To do this, the intermediate class YamlObj is used, representing an abstract YAML node. Each node has a type (YamlScalar, YamlList, or YamlMap), a tag (e.g. tag:yaml.org,2002:str or ? for an non-specific tag), and content (which, depending on the node type, could contain further nodes). This can then be converted to a YAML string or a Fantom object.

This parser is fully compliant with the YAML 1.2.2 specification, other than disallowing nodes which contain themselves.

Reading YAML documents ​

First, YamlReader.parse parses YAML text from a stream into a YamlObj hierarchy. Then, YamlObj.decode finishes the process, transforming the YamlObj into a native Fantom object. (See the schema section on how to fine-tune this process if desired.)

Since multiple documents may be contained within a single YAML stream, the result of YamlReader.parse is always a YamlList tagged with tag:yaml.org,2002:stream which contains the list of documents as content. This way, you may call YamlObj.decode directly on the result, and it will correctly output the list of documents as a list of Fantom objects.

str := "---
        - This is
        - a list!
        - which is in a different
          document from...
        ---
        foo: 1
        map:
        inner list: [a,b,c] # comment
        "
res := YamlReader(str.in).parse.decode

//output
[
  ["This is", "a list!", "which is in a different document from..."],
  ["foo": 1, "map": null, "inner list": ["a","b","c"]]
]

Writing YAML documents ​

This time, the process occurs in reverse: native Fantom objects can be converted to YamlObjs, which can then be written to text.

To convert a Fantom object to a YamlObj, use YamlSchema.encode with a schema of your choice (YamlSchema.core is recommended). Then, to convert that YamlObj to text, call YamlObj.write:

map := ["one key": [1, 2, 3], "multiline\nkey": [:], ["complex", "key"].toImmutable: false]
yamlObj := YamlSchema.core.encode(map)
yamlObj.write

//written to standard out

? - complex
  - key
: false
"multiline\nkey": {}
one key:
 - 1
 - 2
 - 3

You may also use YamlObj.toStr to write this content into a string rather than an OutStream. Note that all objects written either way end with a newline character.

Also note that any serializable object can be encoded in YAML:

  • A simple is just encoded as a string.
  • A complex is encoded as a map, where each field is a map entry.
  • A collection is encoded like a complex, except there is an additional each field that contains the child items.

The object as a whole is then tagged as !fan/pod::Type.

Finally, note that this will always use YAML's block style to write objects, as it is not possible for some YAML objects to be written in flow style and still be preserved. If you would like to write objects in flow style anyway, use JsonOutStream.

Schemas ​

Often, YAML documents contain plain, untagged text, such as Text or 1. (This is represented in YamlObjs by the ? tag.) Sometimes, we want these to be parsed as something other than a Str; for example, we might want 1 to be parsed as an Int, true as a Bool, and so on.

This is where the YamlSchema class comes in. Schemas are all about assigning and reading tags. Different schemas may assign different tags to ?-tagged nodes (reading) or Fantom objects (writing), and may treat tagged nodes differently when creating Fantom objects.

This lists the differences between the built-in schemas (where !! is short for tag:yaml.org,2002:):

+-------------+--------------------------+-------------------------------------+
| Schema      | Recognized tags => types | Main uses                           |
|-------------+--------------------------+-------------------------------------|
| YamlSchema. | !!str   => Str           | Useful when you want all text to be |
| failsafe    | !!seq   => List          | treated literally. For example,     |
|             | !!map   => Map           | empty keys will be treated as ""    |
|             |                          | instead of null.                    |
|-------------+--------------------------+-------------------------------------|
| YamlSchema. | failsafe's tags, +       | Useful if you want to parse JSON-   |
| json        | !!null  => null          | like text that may be mixed with    |
|             | !!bool  => Bool          | YAML's compact styles. Though it    |
|             | !!int   => Int           | won't notice anything style-        |
|             | !!float => Float         | related, it will error if there     |
|             |                          | are plain, untagged strings that    |
|             |                          | are not null/booleans/ints/floats.  |
|-------------+--------------------------+-------------------------------------|
| YamlSchema. | json's tags              | Useful in most cases (and thus      |
| core        |                          | used as the default schema). A wide |
|             |                          | variety of patterns can be used     |
|             |                          | to indicate non-Str content (e.g.   |
|             |                          | ints can be specified in hex or     |
|             |                          | octal). Unlike the JsonSchema, the  |
|             |                          | CoreSchema accepts plain strings.   |
+-------------+--------------------------+-------------------------------------+

See https://yaml.org/spec/1.2.2/#recommended-schemas for more information about each schema and exact definitions of each pattern.

Examples:

str := "int: 1
        empty:
        plain: Text
        large float: -2E+05
        "
parsed   := YamlReader(str.in).parse
failsafe := YamlSchema.failsafe.decode(parsed)
core     := YamlSchema.core.decode(parsed)

//failsafe content - text is just literal
[
  ["int": "1", "empty": "", "plain": "Text", "large float": "-2E+05"]
]

//core content - text is interpreted in different ways
[
  ["int": 1, "empty": null, "plain": "Text", "large float": -20000.0f]
]

Creating custom schemas ​

To interpret additional tags, a custom schema must be created. To do this, it is recommended that you subclass the CoreSchema class (which is itself a subclass of YamlSchema), adding the extra tags you want from there. This makes it possible to keep all of the core schema's tags in use (e.g. 0x05 is still interpreted as the Int 5 without further work needed).

YamlSchemas all have three protected helper methods that you inherit: assignTag, validate, and isRecognized. The first is meant to be used for ?-tagged nodes, giving the node a proper tag, while the second is meant to be used for nodes with specified tags, ensuring that a !!int- tagged node does not contain "true" as content instead of, say, "5". The third just returns true if the schema recognizes a given tag. In each of these methods, if super.isRecognized would return true for a node (or super.assignTag assigns something other than !!str), you should use the superclass's method before defaulting to your own code; e.g. if a node contains the content true, calling super.assignTag will correctly return the !!bool tag. See the implementations of the JSON and core schemas in YamlSchema.fan for examples of this, both which inherit from the failsafe schema.


YamlList ​

const class YamlList : YamlObj

A YamlObj whose content always has the type YamlObj[]. For example, each item on the list below is itself a list:

- - a
  - b
  - c
- [a, b, c]

Constructors

makeCreates a YamlList with the list val as content, found at location loc, with tag as its tag.

Methods

eachIterate the list items
getGet item from the list
valContent value as a list

Slot Details ​


each ​

Void each(|YamlObj| f)

Iterate the list items


get ​

@Operator YamlObj get(Int index)

Get item from the list


make ​

new make(YamlObj[] val, Str tag := "!", FileLoc loc := FileLoc.unknown)

Creates a YamlList with the list val as content, found at location loc, with tag as its tag.


val ​

virtual override YamlObj[] val()

Content value as a list


YamlMap ​

const class YamlMap : YamlObj

A YamlObj whose content always has the type YamlObj:YamlObj. For example, each item on the list below is a map:

- foo: bar
  a: b
- {foo: bar, a: b}

Constructors

makeCreates a YamlMap with the map val as content, found at location loc, with tag as its tag.

Methods

valContent value as a map

Slot Details ​


make ​

new make(YamlObj:YamlObj val, Str tag := "!", FileLoc loc := FileLoc.unknown)

Creates a YamlMap with the map val as content, found at location loc, with tag as its tag.


val ​

virtual override YamlObj:YamlObj val()

Content value as a map


YamlObj ​

@Serializable abstract const class YamlObj : Obj

The base class for objects that represent nodes in a YAML hierarchy. The key information for each node is its tag and content.

See the pod documentation for more information.

Methods

decodeConvenience for schema.decode.
equalsTwo YamlObjs are equal if they have the same type, same tag, and same content.
hashHash is based on tag and content
locThe text location from which this node was parsed.
tagThe node's tag.
toStrReturns write written into a string.
valThe node's content value.
writeTransforms the YAML object back into a string, using block style where applicable.

Slot Details ​


decode ​

Obj? decode(YamlSchema schema := YamlSchema.core)

Convenience for schema.decode.


equals ​

virtual override Bool equals(Obj? that)

Two YamlObjs are equal if they have the same type, same tag, and same content.


hash ​

virtual override Int hash()

Hash is based on tag and content


loc ​

FileLoc loc()

The text location from which this node was parsed.


tag ​

Str tag()

The node's tag. Either a specific tag (e.g. tag:yaml.org,2002:str) or the non-specific tag ?.


toStr ​

virtual override Str toStr()

Returns write written into a string.


val ​

virtual Obj val()

The node's content value. YamlScalars always have content of type Str, YamlLists with content type YamlObj[], and YamlMaps with YamlObj:YamlObj.


write ​

Void write(OutStream out := Env.cur().out())

Transforms the YAML object back into a string, using block style where applicable. The result ends with \n and may span multiple lines.


YamlReader ​

class YamlReader : Obj

Converts YAML text into a hierarchy of YamlObjs, which can in turn be converted into native Fantom objects.

See the pod documentation for more information.

Constructors

makeCreates a new YamlReader that reads YAML content from the given InStream, optionally tracking file location data.
makeFileCreates a new YamlReader that reads YAML content from the given file.

Methods

parseParses the input stream as YAML content, returning each document as its own YamlObj within a larger YamlList.

Slot Details ​


make ​

new make(InStream in, FileLoc loc := FileLoc.unknown)

Creates a new YamlReader that reads YAML content from the given InStream, optionally tracking file location data.


makeFile ​

new makeFile(File file)

Creates a new YamlReader that reads YAML content from the given file.


parse ​

YamlList parse()

Parses the input stream as YAML content, returning each document as its own YamlObj within a larger YamlList.


YamlScalar ​

const class YamlScalar : YamlObj

A YamlObj whose content always has the type Str. For example, each item on the list below is a scalar:

- This is a plain scalar
- "This is a string"
- !!int 5

Constructors

makeCreates a YamlScalar with the string val as content, found at location loc, with tag as its tag.

Methods

valContent value as a string

Slot Details ​


make ​

new make(Str val, Str tag := "?", FileLoc loc := FileLoc.unknown)

Creates a YamlScalar with the string val as content, found at location loc, with tag as its tag.


val ​

virtual override Str val()

Content value as a string


YamlSchema ​

abstract const class YamlSchema : Obj

A class used to convert parsed YamlObjs to native Fantom objects, and vice versa.

Different schemas can recognize different tags; for example, the failsafe schema only recognizes the str, seq, and map tags and ignores all the rest (thus only generating Strs, Lists, and Maps), while the JSON schema also recognizes integers, booleans, etc.

See the pod documentation for more information, especially about the specifics of each built-in schema.

Fields

coreThe default YamlSchema.
failsafeA basic YamlSchema that only generates maps, lists, and strings.
jsonA YamlSchema that can parse all JSON tokens and errors when a plain token is not JSON-compliant.

Methods

decodeRecursively transforms the YAML object into a native Fantom object using this tag resolution schema.
encodeTransforms the native Fantom object into a YamlObj hierarchy that preserves as much information as possible.

Slot Details ​


core ​

const static YamlSchema core

The default YamlSchema.


decode ​

virtual Obj? decode(YamlObj node)

Recursively transforms the YAML object into a native Fantom object using this tag resolution schema.


encode ​

abstract YamlObj encode(Obj? obj)

Transforms the native Fantom object into a YamlObj hierarchy that preserves as much information as possible. The object must be serializable or simple. YamlObjs are encoded as themselves; no further processing is done.


failsafe ​

const static YamlSchema failsafe

A basic YamlSchema that only generates maps, lists, and strings.


json ​

const static YamlSchema json

A YamlSchema that can parse all JSON tokens and errors when a plain token is not JSON-compliant.