<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="rfc7991bis.rnc"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY hy      "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<rfc
  xmlns:xi="http://www.w3.org/2001/XInclude"
  category="info"
  docName="draft-mscaldas-csvpp-02"
  ipr="trust200902"
  submissionType="IETF"
  xml:lang="en"
  version="3">

  <front>
    <title abbrev="CSV++">CSV++ (CSV Plus Plus): Extension to RFC 4180 for Hierarchical Data</title>
    
    <seriesInfo name="Internet-Draft" value="draft-mscaldas-csvpp-02"/>
    
    <author fullname="Marcelo Caldas" initials="M." surname="Caldas">
      <organization>Independent</organization>
      <address>
        <postal>
          <street/>
          <city>Roswell</city>
          <region>Georgia</region>
          <code/>
          <country>USA</country>
        </postal>
        <email>mscaldas@gmail.com</email>
      </address>
    </author>
    
    <date year="2026" month="February" day="25"/>
    
    <area>Applications</area>
    <workgroup>Independent Submission</workgroup>
    
    <keyword>CSV</keyword>
    <keyword>hierarchical data</keyword>
    <keyword>data format</keyword>
    
    <abstract>
      <t>This document specifies CSV++ (CSV Plus Plus), an extension to the Comma-Separated Values (CSV) format defined in RFC 4180. CSV++ adds support for repeating fields (one-to-many relationships) and hierarchicalcomponent structures while maintaining backward compatibility with standard CSV parsers. The extension uses declarative syntax in column headers to define array fields and nested structures, enabling representation of complex real-world data while preserving the simplicity and human-readability of CSV.</t>
    </abstract>
  </front>

  <middle>
    <section anchor="introduction">
      <name>Introduction</name>
      <t>CSV++ extends the CSV format defined in <xref target="RFC4180"/> to support repeating fields (one-to-many relationships) and hierarchical component structures while maintaining backward compatibility with standard CSV parsers.</t>
      
     <section anchor="motivation">
      <name>Motivation</name>
        <t>Traditional CSV files represent flat, tabular data. However, real-world data often contains:</t>
        <ul>
          <li>Repeated values (e.g., multiple phone numbers for one person)</li>
          <li>Structured components (e.g., addresses with street, city, state, zip)</li>
          <li>Nested hierarchies (e.g., addresses with multiple address lines)</li>
        </ul>
  
      <t>CSV++ addresses these limitations by introducing:</t>
  
      <t>While formats like JSON, XML, and YAML excel at representing hierarchical data, they introduce complexity and redundancy that may not be warranted for moderately structured datasets. CSV++ occupies a middle ground by extending CSV's tabular simplicity with hierarchical capabilities, making it particularly suitable for:</t>
      <ul>
        <li>Data interchange where CSV is already established but structure is needed</li>
        <li>Spreadsheet applications where users expect tabular layouts</li>
        <li>Systems with existing CSV infrastructure that need enhanced capabilities</li>
        <li>Scenarios where human readability and editability in text editors is valued</li>
        <li>Applications requiring backward compatibility with legacy CSV parsers</li>
      </ul>
  
      <t>CSV++ maintains CSV's core strengths - simple tooling, wide compatibility, and human-readable plain text - while addressing its limitations with hierarchical data through declarative header syntax.</t>
    </section>
    <section anchor="when-to-use">
      <name>When to Use CSV++</name>
      <t>CSV++ is most appropriate for:</t>
      <ul>
        <li>Moderately structured data (1-3 levels of nesting)</li>
        <li>Environments where CSV is already the established interchange format</li>
        <li>Scenarios requiring backward compatibility with existing CSV infrastructure</li>
        <li>Applications that benefit from self-documenting tabular data with inline structure definitions</li>
        <li>Data that needs to be both machine-parseable and human-readable in plain text</li>
        <li>Large datasets where file size and bandwidth matter, as CSV's columnar format avoids repeating field names in every record (unlike JSON or XML)</li>
      </ul>
      
      <t>For deeply nested hierarchical data (4+ levels), document-oriented formats like JSON or XML may provide better readability and tooling support. CSV++ aims to extend CSV's capabilities for moderately structured data while preserving its tabular nature, not to replace hierarchical data formats.</t>
    </section>
      <section anchor="design-principles">
        <name>Design Principles</name>
        <ol>
          <li><strong>Backward Compatibility:</strong> Standard CSV parsers can read CSV++ files (though they won't interpret the enhanced structure)</li>
          <li><strong>Self-Documenting:</strong> Structure is defined in column headers</li>
          <li><strong>Tabular Readability:</strong> Data maintains a tabular layout suitable for spreadsheet viewing and editing, though deeply nested structures (3+ levels) may be more readable in hierarchical formats like JSON</li>
          <li><strong>Explicit Over Implicit:</strong> Delimiters are declared, not assumed</li>
          <li><strong>Recursively Composable:</strong> Structures can nest to any depth, though practical implementations SHOULD limit nesting to 3-4 levels for readability</li>
        </ol>
      </section>
      <section anchor="requirements">
        <name>Requirements Language</name>
        <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shown here.</t>
      </section>
    </section>

    <section anchor="conformance">
      <name>Conformance with RFC 4180</name>
      <t>CSV++ files MUST conform to <xref target="RFC4180"/> with these specifications:</t>
      <ul>
        <li>Fields are separated by a delimiter (comma by default)</li>
        <li>Records are separated by line breaks (CRLF or LF)</li>
        <li>Fields containing special characters MUST be enclosed in double-quotes</li>
        <li>Double-quotes within quoted fields MUST be escaped by doubling: ""</li>
        <li>The first record MUST be a header row declaring all field names and their types. CSV++ does not support headerless files; a header row is REQUIRED in every CSV++ document.</li>
        <li>MIME type: text/csv</li>
      </ul>
    </section>

    <section anchor="field-separator">
      <name>Field Separator Detection</name>
      <t>The field separator character is detected using the same rules as <xref target="RFC4180"/>. Parsers SHOULD auto-detect the field separator by:</t>
      <ol>
        <li>Scanning the first line (header row)</li>
        <li>Tracking bracket depth: [] and ()</li>
        <li>Identifying characters that appear outside brackets (depth = 0)</li>
        <li>Selecting the most common such character as the field separator</li>
        <li>Common candidates: , (comma), \t (tab), | (pipe), ; (semicolon)</li>
      </ol>
      <t>The comma (,) is the conventional field separator for CSV++ files.</t>
    </section>

    <section anchor="arrays">
      <name>Array Fields (Repetitions)</name>
      
      <section anchor="array-syntax">
        <name>Syntax</name>
        <t>A field containing repeated values is declared in the header using square brackets:</t>
        <sourcecode type="abnf"><![CDATA[
column_name[delimiter]
column_name[]
]]></sourcecode>
        <t>Where:</t>
        <ul>
          <li>column_name - The name of the field</li>
          <li>[delimiter] - The character used to separate repeated values</li>
          <li>[] - Empty brackets use the default array delimiter (first-level arrays only; see below)</li>
        </ul>

        <t>Delimiter Resolution:</t>
        <ol>
          <li>If a delimiter is specified: phone[|] uses |</li>
          <li>If empty brackets at the top (first) nesting level: phone[] uses the tilde (~) as the default delimiter</li>
          <li>If empty brackets at any deeper nesting level: INVALID. Nested arrays MUST explicitly specify a delimiter.</li>
        </ol>

        <t>The tilde (~) is the default array delimiter for first-level (top-level) arrays only.
        When an array appears nested inside a structure or another array, its delimiter MUST be
        explicitly declared and MUST differ from every delimiter already in use at enclosing levels.
        Omitting the delimiter (using []) is not permitted for nested arrays.</t>

        <t>Rationale: because the default tilde (~) is already consumed as the outermost repetition
        separator, reusing it at an inner level would make the data ambiguous and unparseable.
        Requiring an explicit delimiter at each inner level keeps the format unambiguous and
        consistent with the general principle that every nesting level MUST use a distinct delimiter.</t>
      </section>
      
      <section anchor="array-examples">
        <name>Examples</name>
        
        <figure anchor="array-explicit">
          <name>Arrays with Explicit Delimiters</name>
          <sourcecode type="csv"><![CDATA[
id,name,phone[|],email[;]
1,John,555-1234|555-5678|555-9012,john@work.com;john@home.com
2,Jane,555-4444,jane@company.com
]]></sourcecode>
        </figure>
        
        <figure anchor="array-default">
          <name>Arrays with Default Delimiters</name>
          <sourcecode type="csv"><![CDATA[
id,name,phone[],email[]
1,John,555-1234~555-5678~555-9012,john@work.com~john@home.com
2,Jane,555-4444,jane@company.com
]]></sourcecode>
        </figure>
      </section>
      
      <section anchor="empty-values">
        <name>Empty Values</name>
        <t>Empty values in repetitions are represented by consecutive delimiters:</t>
        <figure>
          <sourcecode type="csv"><![CDATA[
id,tags[|]
1,urgent||priority
]]></sourcecode>
        </figure>
        <t>This represents three tags: "urgent", "" (empty), "priority"</t>
      </section>
      
      <section anchor="escaping">
        <name>Escaping</name>
        <t>If a delimiter character appears within a leaf value, that leaf value MUST be quoted per
        <xref target="RFC4180"/>. Quoting rules and the definition of a leaf element are specified
        in <xref target="quoting"/>.</t>
      </section>
    </section>

    <section anchor="structures">
      <name>Structured Fields (Components)</name>
      
      <section anchor="struct-syntax">
        <name>Syntax</name>
        <t>A field containing structured components is declared using parentheses:</t>
        <sourcecode type="abnf"><![CDATA[
column_name[repetition_delim]component_delim(
    comp1 component_delim comp2 ...)
column_name[]component_delim(comp1 component_delim comp2 ...)
column_name[](comp1 component_delim comp2 ...)
column_name(comp1 component_delim comp2 ...)
]]></sourcecode>
        
        <t>Component Delimiter Resolution:</t>
        <ol>
          <li>If specified before (: address^(...) uses ^</li>
          <li>If omitted: address(...) uses the caret (^) as default delimiter</li>
        </ol>
        <t>The caret (^) is recommended as the default component delimiter to avoid conflicts with common data characters.</t>
      </section>
      
      <section anchor="struct-examples">
        <name>Examples</name>
        
        <figure anchor="struct-simple">
          <name>Simple Structure</name>
          <sourcecode type="csv"><![CDATA[
id,name,geo^(lat^lon)
1,Location A,34.0522^-118.2437
2,Location B,40.7128^-74.0060
]]></sourcecode>
        </figure>
        
        <figure anchor="struct-repeated">
          <name>Repeated Structures</name>
          <sourcecode type="csv"><![CDATA[
id,name,address[~]^(street^city^state^zip)
1,John,123 Main St^Los Angeles^CA^90210~456 Oak Ave^New York^NY^10001
2,Jane,789 Pine St^Boston^MA^02101
]]></sourcecode>
        </figure>
      </section>
    </section>

    <section anchor="nesting">
      <name>Nested Structures</name>
      
      <section anchor="nesting-composition">
        <name>Recursive Composition</name>
        <t>Structures can nest arbitrarily deep. Component names can themselves be arrays or structures. Within component names in (...), array and structure syntax applies recursively.</t>
      </section>
      
      <section anchor="nesting-examples">
        <name>Examples</name>
        
        <figure anchor="array-in-struct">
          <name>Array Within Structure</name>
          <sourcecode type="csv"><![CDATA[
id,name,address[~]^(type^lines[;]^city^state^zip)
1,John,home^123 Main;Apt 4^LA^CA^90210~work^456 Oak^NY^NY^10001
]]></sourcecode>
        </figure>
        
        <figure anchor="struct-in-struct">
          <name>Structure Within Structure</name>
          <sourcecode type="csv"><![CDATA[
id,location^(name^coords:(lat:lon))
1,Office^34.05:-118.24
2,Home^40.71:-74.00
]]></sourcecode>
        </figure>
      </section>
      
      <section anchor="delimiter-guidelines">
        <name>Delimiter Selection Guidelines</name>
        <t>To maintain readability and parseability:</t>
        <ol>
          <li><strong>REQUIRED:</strong> Use different delimiters at each nesting level. Nested structures MUST use different component delimiters than their parent</li>
          <li>Use visually distinct delimiters at each level</li>
          <li><strong>Recommended progression:</strong> ~ -> ^ -> ; -> :</li>
          <li>Avoid using the field separator as a component delimiter</li>
          <li>Document delimiter choices for complex schemas</li>
          <li><strong>Recommendation:</strong> Limit nesting to 3-4 levels maximum</li>
        </ol>
      </section>
    </section>

    <section anchor="quoting">
      <name>Quoting and Escaping</name>

      <section anchor="quoting-leaf">
        <name>Leaf Elements</name>
        <t>A <strong>leaf element</strong> is a value that will not be further split by any array
        or component delimiter -- it is the innermost atomic unit at its position in the CSV++
        hierarchy. Examples of leaf elements:</t>
        <ul>
          <li>The value of a simple field</li>
          <li>An individual item within an array (a single repetition after splitting on the array delimiter)</li>
          <li>An individual component value within a structure (a single component after splitting on the component delimiter)</li>
          <li>An individual item within a nested array or nested structure, once all enclosing levels have been split</li>
        </ul>
        <t>RFC 4180 double-quote quoting MUST only be applied to leaf elements. Quoting a value
        that still contains unprocessed array or component delimiters causes those delimiters to
        be treated as literal characters, preventing the parser from splitting the value into its
        constituent parts. This MUST NOT be done.</t>
      </section>

      <section anchor="quoting-valid">
        <name>Valid Quoting (Leaf-Level)</name>
        <t>Quoting is valid when applied to an individual leaf value to escape a delimiter
        character that appears literally within that value:</t>
        <figure>
          <name>Quoting an Individual Array Item (Leaf)</name>
          <sourcecode type="csv"><![CDATA[
id,notes[|]
1,First note|"Second note with | pipe"|Third note
]]></sourcecode>
        </figure>
        <t>The second array item is a leaf; quoting it escapes the literal pipe. The outer pipe
        delimiters that separate the three items remain unquoted and function as separators.</t>

        <figure>
          <name>Quoting an Individual Component Value (Leaf)</name>
          <sourcecode type="csv"><![CDATA[
id,address^(street^city^state^zip)
1,"123 Main St, Apt 4"^Springfield^IL^62701
]]></sourcecode>
        </figure>
        <t>The street component is a leaf; quoting it escapes the comma within the street address.</t>
      </section>

      <section anchor="quoting-invalid">
        <name>Invalid Quoting (Non-Leaf)</name>
        <t>Quoting MUST NOT be applied to a value that contains unprocessed array or component
        delimiters. The following examples are invalid CSV++ and MUST be rejected by parsers:</t>

        <figure>
          <name>Invalid: Quoting an Entire Array Field Value</name>
          <sourcecode type="csv"><![CDATA[
id,notes[|]
1,"First note|Second note|Third note"
]]></sourcecode>
        </figure>
        <t>The field value is quoted at the array level. The pipe characters are treated as literal
        data, so the parser sees a single note rather than three. This defeats the purpose of the
        array declaration and is invalid.</t>

        <figure>
          <name>Invalid: Quoting a Structured Value</name>
          <sourcecode type="csv"><![CDATA[
id,address^(street^city^state^zip)
1,"123 Main St^Springfield^IL^62701"
]]></sourcecode>
        </figure>
        <t>The entire structured value is quoted. The component delimiters are swallowed by the
        quote, so no components can be extracted. This is invalid.</t>

        <figure>
          <name>Invalid: Quoting an Array Item That Is Itself Structured</name>
          <sourcecode type="csv"><![CDATA[
id,address[~]^(street^city^state^zip)
1,"123 Main St^Springfield^IL^62701"~456 Oak Ave^New York^NY^10001
]]></sourcecode>
        </figure>
        <t>The first repetition is quoted at the structure level, preventing component splitting.
        To escape a literal tilde within a component leaf, quote only that leaf value.</t>
      </section>

    </section>

    <section anchor="parsing">
      <name>Parsing</name>
      <t>CSV++ parsers process files in two phases:</t>
      <ol>
        <li><strong>Header Parsing:</strong> Parse column headers to identify field types (simple, array, or structured) and extract delimiter information</li>
        <li><strong>Data Parsing:</strong> For each data row, split fields according to their declared type, respecting <xref target="RFC4180"/> quoting rules for nested delimiters</li>
      </ol>
      <t>The ABNF grammar in <xref target="grammar"/> provides a formal specification. Implementations MUST handle arbitrary nesting depth up to their documented limits.</t>
    </section>

    <section anchor="implementation">
      <name>Implementation Considerations</name>
      
      <section anchor="validation">
        <name>Validation</name>
        <t>Implementations SHOULD validate:</t>
        <ul>
          <li>Matching number of components across repeated structures</li>
          <li>Proper bracket nesting in headers</li>
          <li>Delimiter conflicts (same delimiter at multiple levels)</li>
          <li>MUST reject: Nested structures using the same component delimiter as their parent</li>
          <li>Reasonable nesting depth (recommend warning beyond 3-4 levels)</li>
        </ul>
      </section>
      
      <section anchor="limits">
        <name>Limits</name>
        <t>Implementations MAY impose reasonable limits on:</t>
        <ul>
          <li>Nesting depth (recommended minimum: 10 levels)</li>
          <li>Number of components per structure (recommended minimum: 100)</li>
          <li>Number of repetitions per array (recommended minimum: 1000)</li>
        </ul>
      </section>
    </section>

    <section anchor="mime">
      <name>MIME Type and File Extension</name>
      
      <section anchor="mime-type">
        <name>MIME Type</name>
        <t>CSV++ files use the text/csv media type defined in <xref target="RFC4180"/>.</t>
      </section>
      
      <section anchor="extensions">
        <name>File Extensions</name>
        <ul>
          <li>.csv - Standard extension (recommended for compatibility)</li>
          <li>.csvpp - MAY be used to explicitly indicate CSV++ format</li>
          <li>.csvplus - Alternative explicit extension</li>
        </ul>
      </section>
    </section>

    <section anchor="security">
  <name>Security Considerations</name>

  <t>
    CSV is a long-established and widely deployed format with well-known security considerations.
    As a result, most mature implementations already incorporate mitigations for common CSV-related
    risks. This specification builds on <xref target="RFC4180"/> and remains fully backward
    compatible, but introduces additional structural semantics that may increase parser complexity
    and therefore require corresponding care in implementations.
  </t>

  <section anchor="injection-risks">
    <name>Injection and Interpretation Risks</name>
    <t>
      Malicious data may attempt to inject delimiters or structural markers to influence parsing
      behavior. Implementations MUST respect <xref target="RFC4180"/> quoting rules. Delimiters and
      structural markers appearing within quoted fields MUST be treated as literal values.
    </t>
    <t>
      The default delimiters defined by this specification are intentionally chosen to be neutral
      and to avoid characters commonly associated with executable or control semantics. In
      addition, the explicit declaration of any non-default delimiters in the header allows
      parsers to establish expectations up front, reducing the likelihood of delimiter injection
      or ambiguous interpretation.
    </t>
    <t>
      As with traditional CSV, some spreadsheet applications interpret certain values (e.g. those
      beginning with "=", "+", "-", or "@") as formulas. This specification does not attempt to
      redefine or mitigate spreadsheet formula evaluation; producers and consumers SHOULD continue
      to apply established best practices when targeting such environments.
    </t>
  </section>

  <section anchor="complexity-attacks">
    <name>Complexity and Resource Exhaustion</name>
    <t>
      Deeply nested, malformed, or highly repetitive structures may lead to excessive CPU or memory
      consumption during parsing.
    </t>
    <t>Implementations SHOULD:</t>
    <ul>
      <li>Enforce configurable limits on nesting depth and repetition</li>
      <li>Enforce reasonable limits on field sizes and record length</li>
      <li>Fail fast on structurally invalid input</li>
      <li>Prefer streaming or incremental parsing for large files</li>
      <li>Validate headers and structural definitions before processing data rows</li>
    </ul>
  </section>

  <section anchor="tool-interoperability">
    <name>Mixed-Tool Interoperability</name>
    <t>
      CSV++ files may transit through tools unaware of the extended semantics, potentially resulting
      in loss of structure or unintended reinterpretation. Implementations used in
      security-sensitive pipelines SHOULD explicitly validate inputs and avoid implicit trust when
      moving between CSV-aware and CSV++-aware tools.
    </t>
  </section>

  <section anchor="encoding">
    <name>Encoding Issues</name>
    <t>
      Files SHOULD use UTF-8 encoding. Implementations SHOULD detect and handle encoding errors.
      A BOM (Byte Order Mark) MAY be present.
    </t>
  </section>

  <section anchor="iana">
  <name>IANA Considerations</name>
  <t>
    This document has no IANA actions.
  </t>
  <t>
    CSV++ files use the <tt>text/csv</tt> media type as defined in
    <xref target="RFC4180"/>. The format is fully backward compatible with
    standard CSV parsers; implementations unaware of the extensions defined
    in this document will process CSV++ files as conventional CSV, ignoring
    extended semantics.
  </t>
</section>
</section>
<section anchor="changelog" numbered="false">
  <name>Change Log</name>
  <t>Changes from -01 to -02:</t>
  <ul>
    <li>Header row is now REQUIRED (MUST) in all CSV++ documents; headerless files are not supported.</li>
    <li>Removed language suggesting the header row is optional (was: "MAY be a header record").</li>
    <li>Removed references to auto-identification of field types from data without a header.</li>
    <li>Clarified that the tilde (~) default array delimiter applies to first-level (top-level) arrays only. Nested arrays MUST explicitly specify a delimiter distinct from all enclosing levels; using empty brackets ([]) in a nested array is invalid.</li>
    <li>Added Quoting and Escaping section defining leaf elements. RFC 4180 quoting MUST only be applied to leaf elements (atomic values not further split by any delimiter). Quoting non-leaf values (entire arrays or structured fields) is explicitly invalid and MUST be rejected by parsers.</li>
  </ul>
  <t>Changes from -00 to -01:</t>
  <ul>
    <li>Enhanced Motivation section to contrast with JSON/XML</li>
    <li>Added "When to Use CSV++" section</li>
    <li>Improved scaping example on 4.4</li>
    <li>Updated Security section to include CSV injection considerations.</li>
  </ul>
</section>
  </middle>

  <back>
    <references>
      <name>References</name>
      
      <references>
        <name>Normative References</name>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4180.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
      </references>
      
      <references>
        <name>Informative References</name>
      </references>
    </references>

    <section anchor="grammar">
      <name>Grammar (ABNF)</name>
      <sourcecode type="abnf"><![CDATA[
csvpp-file     = header-row data-rows

header-row     = field *(field-sep field) CRLF
data-rows      = *(data-row CRLF)
data-row       = value *(field-sep value)

field          = simple-field / array-field / 
                 struct-field / array-struct-field
simple-field   = name
array-field    = name "[" [delimiter] "]"
struct-field   = name [component-delim] "(" component-list ")"
array-struct-field = name "[" [delimiter] "]" 
                     [component-delim] "(" component-list ")"

component-list = component *(component-delim component)
component      = simple-field / array-field / 
                 struct-field / array-struct-field

name           = 1*field-char
field-char     = ALPHA / DIGIT / "_" / "-"
delimiter      = CHAR
component-delim = CHAR

value          = quoted-value / unquoted-value
quoted-value   = DQUOTE *(textdata / escaped-quote) DQUOTE
unquoted-value = *textdata
escaped-quote  = DQUOTE DQUOTE
textdata       = <any character except DQUOTE, CRLF, or field-sep>
]]></sourcecode>
    </section>

    <section anchor="examples-appendix">
      <name>Complete Examples</name>
      
      <figure anchor="example-ecommerce">
        <name>E-commerce Order</name>
        <sourcecode type="csv"><![CDATA[
id,cust,items[~]^(sku^name^qty^price^opts[;]:(k:v))
1,Alice,S1^Shirt^2^20^sz:M;col:blu~S2^Pant^1^50^sz:32
]]></sourcecode>
      </figure>
    </section>

    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>This specification was inspired by the HL7 Version 2.x delimiter hierarchy and the need for a simple, human-readable format for hierarchical data that maintains compatibility with existing CSV tools.</t>
    </section>
  </back>
</rfc>
