В YAML должен ли цитируемый скаляр интерпретироваться парсером как строка?

Я видел в интернете совет, что если вы хотите, чтобы скалярное значение YAML обрабатывалось как строка, вы должны заключить его в кавычки:

foo : "2018-04-17"

В приведенном выше примере этот совет предназначен для того, чтобы сказать мне, что значение 2018-04-17 будет обработан любым данным синтаксическим анализатором YAML как строковый тип его родного языка. Например, SnakeYAML, если бы этот совет был верным, интерпретировал бы это как java.lang.Stringа не как java.util.Date, (Как это бывает, SnakeYAML интерпретирует это как java.util.Date, цитаты или нет, поэтому я задаю этот вопрос.)

Но хотя этот совет может работать с любым конкретным парсером, я не вижу, где в YAML 1.2. Спецификация этот совет может прийти. Самое близкое, что я могу найти, это следующее предложение:

YAML позволяет представлять скаляры в нескольких форматах. Например, целое число "11"Также может быть написано как"0xB". Теги должны указывать механизм для преобразования форматированного содержимого в каноническую форму для использования в тестировании на равенство. Как и стиль узла, формат представляет собой детали представления и не отражается в дереве сериализации и графе представления.

И этот:

Скалярный стиль является деталью представления и не должен использоваться для передачи информации о содержимом, за исключением того, что простые скаляры различаются с целью разрешения тегов.

И этот:

Обратите внимание, что разрешение не должно учитывать детали представления, такие как комментарии, отступы и стиль узла.

Тем не менее, я вижу много документов YAML, которые основаны на рекомендациях двойных кавычек "значение означает, что это будет проанализировано как строка", что заставляет меня думать, что я что-то неправильно понял. Есть ли споры по этому вопросу?

1 ответ

Решение

Соответствующий раздел из спецификации YAML 1.1 (обратите внимание, что SnakeYaml - это YAML 1.1, и поэтому спецификация 1.2 не обязательно применяется):

Не требуется, чтобы все теги полного представления были явно указаны в символьном потоке. Во время синтаксического анализа узлам, которые пропускают тег, присваивается неспецифический тег: "?" Для простых скаляров и "!" Для всех остальных узлов. [...]

Рекомендуется разрешить узлы, имеющие неспецифический тег "!", Как "tag:yaml.org,2002:seq", "tag:yaml.org,2002:map" или "tag:yaml.org,2002:str”в зависимости от вида узла. Это соглашение позволяет автору потока символов YAML осуществлять некоторую степень контроля над процессом разрешения тегов. Путем явного указания простого скаляра с неспецифическим тегом "!" Узел разрешается в виде строки, как если бы он был заключен в кавычки или записан в стиле блока. Обратите внимание, однако, что каждое приложение может переопределить это поведение. Например, приложение может автоматически определять тип языка программирования, используемый в исходном коде, представленном как непрозрачный скаляр, и разрешать его соответствующим образом.

Таким образом, чтобы подвести итог, процессор YAML не обязан анализировать скаляры в кавычках как строки, и YAML также не определяет, какой тип tag:yaml.org,2002:str отображается на. И на самом деле, большинство реализаций YAML следуют только частям этого совета. Например, если вы десериализуете YAML в POJO/JavaBean с помощью SnakeYaml, вы обычно не используете какие-либо явные теги в своем YAML, но ваши сопоставления разрешаются в соответствующие классы Java в структуре корневого класса, а не в общий Map это то, что предлагает этот совет (так как все отображения без явных тегов получают ! неспецифический тег).

Обратите внимание, что это было изменено в YAML 1.2:

Во время синтаксического анализа узлам, не имеющим явного тега, присваивается неспецифический тег: "!" Для непростых скаляров и "?" Для всех остальных узлов.

Это ближе к большинству реализаций, но, например, если вы десериализуете в класс class Foo { String bar; }, это все равно будет загружать хотя bar это не строка, а имя поля:

"bar": some value

Таким образом, совет для использования YAML заключается в том, чтобы указать желаемую структуру на стороне приложения - в SnakeYaml вы бы задали тип корневого класса, и тогда каждое значение будет отображаться на требуемый тип в его точке иерархии, если оно может отображать там, независимо от того, цитируется он или нет. В целом, для приложения имеет больше смысла указывать, какой тип значения он ожидает по всей иерархии, а не автор YAML, чтобы сделать это через кавычки. Это также соответствует спецификации YAML, которая говорит

Разрешение тега узла должно зависеть только от следующих трех параметров: (1) неспецифический тег узла, (2) путь, ведущий от корня к узлу, и (3) содержимое (и, следовательно, вид) узла.

Разрешение тега - это термин YAML для определения типа цели. И разрешено определять целевой тип на основе его положения в иерархии: корневой тип определяется тем фактом, что элемент является корнем документа YAML, а в случае SnakeYaml может подаваться через API. Все остальные типы определяются тем, что они являются потомками корневого типа.

Последнее замечание: если вы действительно хотите, чтобы что-то было строкой, !!str 2018-04-17 будет делать, так как он устанавливает определенный тег для узла.

Другие вопросы по тегам