2 .\" # Copyright (c) 2014, Juniper Networks, Inc.
3 .\" # All rights reserved.
4 .\" # This SOFTWARE is licensed under the LICENSE provided in the
5 .\" # ../Copyright file. By downloading, installing, copying, or
6 .\" # using the SOFTWARE, you agree to be bound by the terms of that
8 .\" # Phil Shafer, July 2014
15 .Nd content of format descriptors for xo_emit
19 uses format strings to control the rendering of data into
20 various output styles, including
26 Each format string contains a set of zero or more
27 .Dq field descriptions ,
28 which describe independent data fields.
29 Each field description contains a set of
34 .Dq format descriptors .
37 what the field is and how to treat it, while the format descriptors are
38 formatting instructions using
39 .Xr printf 3 Ns -style
40 format strings, telling
42 how to format the field.
43 The field description is placed inside
44 a set of braces, with a colon
46 after the modifiers and a slash
48 before each format descriptors.
49 Text may be intermixed with
50 field descriptions within the format string.
52 The field description is given as follows:
53 .Bd -literal -offset indent
54 '{' [ role | modifier ]* ':' [ content ]
55 [ '/' field-format [ '/' encoding-format ]] '}'
58 The role describes the function of the field, while the modifiers
59 enable optional behaviors.
60 The contents, field-format, and
61 encoding-format are used in varying ways, based on the role.
62 These are described in the following sections.
64 In the following example, three field descriptors appear.
66 is a padding field containing three spaces of padding, the second is a
67 label ("In stock"), and the third is a value field ("in-stock").
68 The in-stock field has a "%u" format that will parse the next argument
71 function as an unsigned integer.
72 .Bd -literal -offset indent
73 xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\\n", 65);
76 This single line of code can generate text ("In stock: 65\\n"), XML
77 ("<in-stock>65</in-stock>"), JSON ('"in-stock": 6'), or HTML (too
78 lengthy to be listed here).
80 Modifiers are optional, and indicate the role and formatting of the
82 The roles are listed below; only one role is permitted:
84 .Bl -column "M" "Name12341234"
85 .It Sy "M Name Description"
86 .It D "decoration " "Field is non-text (e.g. colon, comma)"
87 .It E "error " "Field is an error message"
88 .It L "label " "Field is text that prefixes a value"
89 .It N "note " "Field is text that follows a value"
90 .It P "padding " "Field is spaces needed for vertical alignment"
91 .It T "title " "Field is a title value for headings"
92 .It U "units " "Field is the units for the previous value field"
93 .It V "value " "Field is the name of field (the default)"
94 .It W "warning " "Field is a warning message"
95 .It \&[ "start anchor" "Begin a section of anchored variable-width text"
96 .It \&] "stop anchor " "End a section of anchored variable-width text"
99 .Ss The Decoration Role ({D:})
100 Decorations are typically punctuation marks such as colons,
101 semi-colons, and commas used to decorate the text and make it simpler
103 By marking these distinctly, HTML usage scenarios
104 can use CSS to direct their display parameters.
105 .Bd -literal -offset indent
106 xo_emit("{D:((}{:name}{D:))}\\n", name);
108 .Ss The Label Role ({L:})
109 Labels are text that appears before a value.
110 .Bd -literal -offset indent
111 xo_emit("{Lwc:Cost}{:cost/%u}\\n", cost);
113 .Ss The Note Role ({N:})
114 Notes are text that appears after a value.
115 .Bd -literal -offset indent
116 xo_emit("{:cost/%u} {N:per year}\\n", cost);
118 .Ss The Padding Role ({P:})
119 Padding represents whitespace used before and between fields.
120 The padding content can be either static, when placed directly within
121 the field descriptor, or a printf-style format descriptor can be used,
122 if preceded by a slash ("/"):
123 .Bd -literal -offset indent
124 xo_emit("{P: }{Lwc:Cost}{:cost/%u}\\n", cost);
125 xo_emit("{P:/30s}{Lwc:Cost}{:cost/%u}\\n", "", cost);
127 .Ss The Title Role ({T:})
128 Titles are heading or column headers that are meant to be displayed to
130 The title can be either static, when placed directly within
131 the field descriptor, or a printf-style format descriptor can be used,
132 if preceded by a slash ("/"):
133 .Bd -literal -offset indent
134 xo_emit("{T:Interface Statistics}\\n");
135 xo_emit("{T:/%20.20s}{T:/%6.6s}\\n", "Item Name", "Cost");
137 .Ss The Units Role ({U:})
138 Units are the dimension by which values are measured, such as degrees,
139 miles, bytes, and decibels.
140 The units field carries this information
141 for the previous value field.
142 .Bd -literal -offset indent
143 xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\\n", miles);
146 Note that the sense of the 'w' modifier is reversed for units;
147 a blank is added before the contents, rather than after it.
151 flag is set, units are rendered in XML as the
154 .Bd -literal -offset indent
155 <distance units="miles">50</distance>
158 Units can also be rendered in HTML as the "data-units" attribute:
159 .Bd -literal -offset indent
160 <div class="data" data-tag="distance" data-units="miles"
161 data-xpath="/top/data/distance">50</div>
163 .Ss The Value Role ({V:} and {:})
164 The value role is used to represent the a data value that is
165 interesting for the non-display output styles (XML and JSON).
167 is the default role; if no other role designation is given, the field
169 The field name must appear within the field descriptor,
170 followed by one or two format descriptors.
172 descriptor is used for display styles (TEXT and HTML), while the
173 second one is used for encoding styles (XML and JSON).
175 format is given, the encoding format defaults to the first format,
176 with any minimum width removed.
177 If no first format is given, both
178 format descriptors default to "%s".
179 .Bd -literal -offset indent
180 xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\\n",
181 length, width, height);
182 xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\\n,
185 .Ss The Anchor Modifiers ({[:} and {]:})
186 The anchor roles allow a set of strings by be padded as a group,
187 but still be visible to
191 or stop anchor can give a field width and it can be either directly in
192 the descriptor or passed as an argument.
193 Any fields between the start
194 and stop anchor are padded to meet the minimum width given.
196 To give a width directly, encode it as the content of the anchor tag:
197 .Bd -literal -offset indent
198 xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\\n", min, max);
201 To pass a width as an argument, use "%d" as the format, which must
202 appear after the "/".
203 Note that only "%d" is supported for widths.
204 Using any other value could ruin your day.
205 .Bd -literal -offset indent
206 xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\\n", width, min, max);
209 If the width is negative, padding will be added on the right, suitable
210 for left justification.
211 Otherwise the padding will be added to the
212 left of the fields between the start and stop anchors, suitable for
214 If the width is zero, nothing happens.
216 number of columns of output between the start and stop anchors is less
217 than the absolute value of the given width, nothing happens.
219 Widths over 8k are considered probable errors and not supported.
222 is set, a warning will be generated.
224 The modifiers can also include the following flags, which modify the
225 content emitted for some output styles:
227 .Bl -column M "Name12341234"
228 .It Sy M "Name Description"
229 .It c "colon " "A colon ("":"") is appended after the label"
230 .It d "display " "Only emit field for display styles (text/HTML)"
231 .It e "encoding " "Only emit for encoding styles (XML/JSON)"
232 .It k "key " "Field is a key, suitable for XPath predicates"
233 .It n "no-quotes " "Do not quote the field when using JSON style"
234 .It q "quotes " "Quote the field when using JSON style"
235 .It w "white space " "A blank ("" "") is appended after the label"
238 For example, the modifier string "Lwc" means the field has a label
239 role (text that describes the next field) and should be followed by a
240 colon ('c') and a space ('w').
241 The modifier string "Vkq" means the
242 field has a value role, that it is a key for the current instance, and
243 that the value should be quoted when encoded for JSON.
244 .Ss The Colon Modifier ({c:})
245 The colon modifier appends a single colon to the data value:
246 .Bd -literal -offset indent
248 xo_emit("{Lc:Name}{:name}\\n", "phil");
253 The colon modifier is only used for the TEXT and HTML output
255 It is commonly combined with the space modifier ('{w:}').
256 It is purely a convenience feature.
257 .Ss The Display Modifier ({d:})
258 The display modifier indicated the field should only be generated for
259 the display output styles, TEXT and HTML.
260 .Bd -literal -offset indent
262 xo_emit("{Lcw:Name}{d:name} {:id/%d}\\n", "phil", 1);
269 The display modifier is the opposite of the encoding modifier, and
270 they are often used to give to distinct views of the underlying data.
271 .Ss The Encoding Modifier ({e:})
272 The display modifier indicated the field should only be generated for
273 the display output styles, TEXT and HTML.
274 .Bd -literal -offset indent
276 xo_emit("{Lcw:Name}{:name} {e:id/%d}\\n", "phil", 1);
280 <name>phil</name><id>1</id>
283 The encoding modifier is the opposite of the display modifier, and
284 they are often used to give to distinct views of the underlying data.
285 .Ss The Key Modifier ({k:})
286 The key modifier is used to indicate that a particular field helps
287 uniquely identify an instance of list data.
288 .Bd -literal -offset indent
290 xo_open_list("user");
291 for (i = 0; i < num_users; i++) {
292 xo_open_instance("user");
293 xo_emit("User {k:name} has {:count} tickets\\n",
294 user[i].u_name, user[i].u_tickets);
295 xo_close_instance("user");
297 xo_close_list("user");
300 Currently the key modifier is only used when generating XPath values
301 for the HTML output style when
303 is set, but other uses are likely in the near future.
304 .Ss The Leaf-List Modifier ({l:})
305 The leaf-list modifier is used to distinguish lists where each
306 instance consists of only a single value. In XML, these are
307 rendered as single elements, where JSON renders them as arrays.
308 .Bd -literal -offset indent
310 xo_open_list("user");
311 for (i = 0; i < num_users; i++) {
312 xo_emit("Member {l:name}\n", user[i].u_name);
314 xo_close_list("user");
319 "user": [ "phil", "pallavi" ]
321 .Ss The No-Quotes Modifier ({n:})
322 The no-quotes modifier (and its twin, the 'quotes' modifier) affect
323 the quoting of values in the JSON output style.
325 string values, but no quotes for numeric, boolean, and null data.
327 applies a simple heuristic to determine whether quotes are
328 needed, but often this needs to be controlled by the caller.
329 .Bd -literal -offset indent
331 const char *bool = is_true ? "true" : "false";
332 xo_emit("{n:fancy/%s}", bool);
336 .Ss The Quotes Modifier ({q:})
337 The quotes modifier (and its twin, the 'no-quotes' modifier) affect
338 the quoting of values in the JSON output style.
340 string values, but no quotes for numeric, boolean, and null data.
342 applies a simple heuristic to determine whether quotes are
343 needed, but often this needs to be controlled by the caller.
344 .Bd -literal -offset indent
346 xo_emit("{q:time/%d}", 2014);
350 .Ss The White Space Modifier ({w:})
351 The white space modifier appends a single space to the data value:
352 .Bd -literal -offset indent
354 xo_emit("{Lw:Name}{:name}\\n", "phil");
359 The white space modifier is only used for the TEXT and HTML output
361 It is commonly combined with the colon modifier ('{c:}').
362 It is purely a convenience feature.
364 Note that the sense of the 'w' modifier is reversed for the units role
365 ({Uw:}); a blank is added before the contents, rather than after it.
367 The field format is similar to the format string for
369 Its use varies based on the role of the field, but generally is used to
370 format the field's contents.
372 If the format string is not provided for a value field, it defaults
375 Note a field definition can contain zero or more printf-style
377 which are sequences that start with a '%' and end with
378 one of following characters: "diouxXDOUeEfFgGaAcCsSp".
380 is matched by one of more arguments to the
384 The format string has the form:
385 .Bd -literal -offset indent
386 '%' format-modifier * format-character
389 The format- modifier can be:
392 a '#' character, indicating the output value should be prefixed with
393 '0x', typically to indicate a base 16 (hex) value.
395 a minus sign ('-'), indicating the output value should be padded on
396 the right instead of the left.
398 a leading zero ('0') indicating the output value should be padded on the
399 left with zeroes instead of spaces (' ').
401 one or more digits ('0' - '9') indicating the minimum width of the
403 If the width in columns of the output value is less than
404 the minimum width, the value will be padded to reach the minimum.
406 a period followed by one or more digits indicating the maximum
407 number of bytes which will be examined for a string argument, or the maximum
408 width for a non-string argument.
409 When handling ASCII strings this
410 functions as the field width but for multi-byte characters, a single
411 character may be composed of multiple bytes.
413 will never dereference memory beyond the given number of bytes.
415 a second period followed by one or more digits indicating the maximum
416 width for a string argument.
417 This modifier cannot be given for non-string arguments.
419 one or more 'h' characters, indicating shorter input data.
421 one or more 'l' characters, indicating longer input data.
423 a 'z' character, indicating a 'size_t' argument.
425 a 't' character, indicating a 'ptrdiff_t' argument.
427 a ' ' character, indicating a space should be emitted before
430 a '+' character, indicating sign should emitted before any number.
433 Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be
436 The format character is described in the following table:
438 .Bl -column C "Argument Type12"
439 .It Sy "C Argument Type Format"
440 .It d "int " "base 10 (decimal)"
441 .It i "int " "base 10 (decimal)"
442 .It o "int " "base 8 (octal)"
443 .It u "unsigned " "base 10 (decimal)"
444 .It x "unsigned " "base 16 (hex)"
445 .It X "unsigned long " "base 16 (hex)"
446 .It D "long " "base 10 (decimal)"
447 .It O "unsigned long " "base 8 (octal)"
448 .It U "unsigned long " "base 10 (decimal)"
449 .It e "double " "[-]d.ddde+-dd"
450 .It E "double " "[-]d.dddE+-dd"
451 .It f "double " "[-]ddd.ddd"
452 .It F "double " "[-]ddd.ddd"
453 .It g "double " "as 'e' or 'f'"
454 .It G "double " "as 'E' or 'F'"
455 .It a "double " "[-]0xh.hhhp[+-]d"
456 .It A "double " "[-]0Xh.hhhp[+-]d"
457 .It c "unsigned char " "a character"
458 .It C "wint_t " "a character"
459 .It s "char * " "a UTF-8 string"
460 .It S "wchar_t * " "a unicode/WCS string"
461 .It p "void * " "'%#lx'"
464 The 'h' and 'l' modifiers affect the size and treatment of the
466 .Bl -column "Mod" "d, i " "o, u, x, X "
467 .It Sy "Mod" "d, i " "o, u, x, X"
468 .It "hh " "signed char " "unsigned char"
469 .It "h " "short " "unsigned short"
470 .It "l " "long " "unsigned long"
471 .It "ll " "long long " "unsigned long long"
472 .It "j " "intmax_t " "uintmax_t"
473 .It "t " "ptrdiff_t " "ptrdiff_t"
474 .It "z " "size_t " "size_t"
475 .It "q " "quad_t " "u_quad_t"
478 .Ss UTF-8 and Locale Strings
483 will handle turning them
484 into locale-based strings for display to the user.
486 For strings, the 'h' and 'l' modifiers affect the interpretation of
487 the bytes pointed to argument.
488 The default '%s' string is a 'char *'
489 pointer to a string encoded as UTF-8.
490 Since UTF-8 is compatible with
496 'wchar_t *' pointer to a wide-character string, encoded as 32-bit
498 '%hs' expects a 'char *' pointer to a multi-byte
499 string encoded with the current locale, as given by the
504 environment variables.
505 The first of this list of
506 variables is used and if none of the variables are set, the locale defaults to
511 convert these arguments as needed to either UTF-8 (for XML, JSON, and
512 HTML styles) or locale-based strings for display in text style.
513 .Bd -literal -offset indent
514 xo_emit("All strings are utf-8 content {:tag/%ls}",
515 L"except for wide strings");
518 "%S" is equivalent to "%ls".
520 For example, a function is passed a locale-base name, a hat size,
522 The hat size is formatted in a UTF-8 (ASCII)
523 string, and the time value is formatted into a wchar_t string.
524 .Bd -literal -offset indent
525 void print_order (const char *name, int size,
528 const char *size_val = "unknown";
531 snprintf(buf, sizeof(buf), "%d", size);
536 wcsftime(when, sizeof(when), L"%d%b%y", timep);
538 xo_emit("The hat for {:name/%hs} is {:size/%s}.\\n",
540 xo_emit("It was ordered on {:order-time/%ls}.\\n",
545 It is important to note that
547 will perform the conversion
548 required to make appropriate output.
549 Text style output uses the
550 current locale (as described above), while XML, JSON, and HTML use
553 UTF-8 and locale-encoded strings can use multiple bytes to encode one
555 The traditional "precision'" (aka "max-width") value
556 for "%s" printf formatting becomes overloaded since it specifies both
557 the number of bytes that can be safely referenced and the maximum
558 number of columns to emit.
560 uses the precision as the former,
561 and adds a third value for specifying the maximum number of columns.
563 In this example, the name field is printed with a minimum of 3 columns
565 Up to ten bytes are in used in filling those columns.
566 .Bd -literal -offset indent
567 xo_emit("{:name/%3.10.6s}", name);
569 .Ss Characters Outside of Field Definitions
570 Characters in the format string that are not part of a field definition are
571 copied to the output for the TEXT style, and are ignored for the JSON
573 For HTML, these characters are placed in a <div> with class "text".
574 .Bd -literal -offset indent
576 xo_emit("The hat is {:size/%s}.\\n", size_val);
578 The hat is extra small.
580 <size>extra small</size>
582 "size": "extra small"
584 <div class="text">The hat is </div>
585 <div class="data" data-tag="size">extra small</div>
586 <div class="text">.</div>
588 .Ss "%n" is Not Supported
590 does not support the '%n' directive.
591 It is a bad idea and we
593 .Ss The Encoding Format (eformat)
594 The "eformat" string is the format string used when encoding the field
596 If not provided, it defaults to the primary format
597 with any minimum width removed.
598 If the primary is not given, both default to "%s".
600 In this example, the value for the number of items in stock is emitted:
601 .Bd -literal -offset indent
602 xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\\n",
606 This call will generate the following output:
607 .Bd -literal -offset indent
611 <in-stock>144</in-stock>
616 <div class="padding"> </div>
617 <div class="label">In stock</div>
618 <div class="decoration">:</div>
619 <div class="padding"> </div>
620 <div class="data" data-tag="in-stock">144</div>
624 Clearly HTML wins the verbosity award, and this output does
629 data, which would expand the penultimate line to:
630 .Bd -literal -offset indent
631 <div class="data" data-tag="in-stock"
632 data-xpath="/top/data/item/in-stock"
634 data-help="Number of items in stock">144</div>
636 .Sh WHAT MAKES A GOOD FIELD NAME?
637 To make useful, consistent field names, follow these guidelines:
639 .Ss Use lower case, even for TLAs
640 Lower case is more civilized.
641 Even TLAs should be lower case
642 to avoid scenarios where the differences between "XPath" and
643 "Xpath" drive your users crazy.
644 Using "xpath" is simpler and better.
645 .Ss Use hyphens, not underscores
646 Use of hyphens is traditional in XML, and the
648 flag can be used to generate underscores in JSON, if desired.
649 But the raw field name should use hyphens.
651 Do not abbreviate especially when the abbreviation is not obvious or
653 Use "data-size", not "dsz" or "dsize".
655 "interface" instead of "ifname", "if-name", "iface", "if", or "intf".
656 .Ss Use <verb>-<units>
657 Using the form <verb>-<units> or <verb>-<classifier>-<units> helps in
658 making consistent, useful names, avoiding the situation where one app
659 uses "sent-packet" and another "packets-sent" and another
660 "packets-we-have-sent".
661 The <units> can be dropped when it is
662 obvious, as can obvious words in the classification.
663 Use "receive-after-window-packets" instead of
664 "received-packets-of-data-after-window".
665 .Ss Reuse existing field names
666 Nothing is worse than writing expressions like:
667 .Bd -literal -offset indent
668 if ($src1/process[pid == $pid]/name ==
669 $src2/proc-table/proc/p[process-id == $pid]/proc-name) {
674 Find someone else who is expressing similar data and follow their
675 fields and hierarchy.
676 Remember the quote is not
677 .Dq Consistency is the hobgoblin of little minds
679 .Dq A foolish consistency is the hobgoblin of little minds .
680 .Ss Think about your users
681 Have empathy for your users, choosing clear and useful fields that
682 contain clear and useful data.
683 You may need to augment the display content with
685 calls or "{e:}" fields to make the data useful.
686 .Ss Do not use an arbitrary number postfix
687 What does "errors2" mean?
689 "errors-after-restart" would be a better choice.
690 Think of your users, and think of the future.
691 If you make "errors2", the next guy will happily make
692 "errors3" and before you know it, someone will be asking what is the
693 difference between errors37 and errors63.
694 .Ss Be consistent, uniform, unsurprising, and predictable
695 Think of your field vocabulary as an API.
697 expressive, meaningful, direct, and obvious.
699 application's programmer to move between without the need to
700 understand a variety of opinions on how fields are named.
702 see the system as a single cohesive whole, not a sack of cats.
704 Field names constitute the means by which client programmers interact
706 By choosing wise names now, you are making their lives better.
710 to find errors in your field descriptors, use
712 to spell check your field names and to detect different
713 names for the same data.
716 .Dq dropped-too-short
717 are both reasonable names, but using them both will lead users to ask the
718 difference between the two fields.
719 If there is no difference,
720 use only one of the field names.
721 If there is a difference, change the
722 names to make that difference more obvious.
723 .Sh ADDITIONAL DOCUMENTATION
724 Complete documentation can be found on github:
725 .Bd -literal -offset indent
726 http://juniper.github.io/libxo/libxo-manual.html
731 .Bd -literal -offset indent
732 https://github.com/Juniper/libxo
735 The latest release of
738 .Bd -literal -offset indent
739 https://github.com/Juniper/libxo/releases