<https://docs.linkeddatahub.com/tutorial/data/>
        a       <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#Item>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#_1>
                <https://docs.linkeddatahub.com/tutorial/data/#content>;
        <http://purl.org/dc/terms/created>
                "2026-09-29T09:52:42.134Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>;
        <http://purl.org/dc/terms/creator>
                <https://admin.linkeddatahub.com/acl/agents/5ba81960-d511-4a3b-8b9a-cb5bb278dd95/#this>;
        <http://purl.org/dc/terms/description>
                "Import CSV data using SPARQL mappings";
        <http://purl.org/dc/terms/title>
                "Data";
        <http://rdfs.org/sioc/ns#has_container>
                <https://docs.linkeddatahub.com/tutorial/>;
        <http://www.w3.org/ns/auth/acl#owner>
                <https://admin.linkeddatahub.com/acl/agents/5ba81960-d511-4a3b-8b9a-cb5bb278dd95/#this> .

<https://docs.linkeddatahub.com/tutorial/data/#content>
        a       <https://w3id.org/atomgraph/linkeddatahub#XHTML>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#value>
                "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n    <p class=\"ldh-body-lg\">Import CSV data using SPARQL mappings</p>\n    <p>Northwind's data ships as plain CSV files. The first rows of <samp>categories.csv</samp>:</p>\n    <pre>categoryID,categoryName,description,pictureHash\n1,Beverages,Soft drinks coffees teas beers and ales,ec56b79671b30ecb98316d9b766fba198286b3b6\n2,Condiments,Sweet and savory sauces relishes spreads and seasonings,7e9f535a3bf693ec856702856fffd3be5a3df4f1</pre>\n    <p class=\"exhibit-links\">Source: <a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps/blob/master/demo/northwind-traders/categories/categories.csv\" target=\"_blank\">categories/categories.csv</a></p>\n    <p>LinkedDataHub <a href=\"../../reference/imports/csv/\" target=\"_blank\">imports CSV</a> by running a SPARQL <code>CONSTRUCT</code> mapping over each\n        row: the row's cells are bound as properties of a row resource, and the query builds the RDF you want from them. Each column becomes a predicate named after its header, resolved against the\n        imported file's URI — the <samp>categoryID</samp> column binds as <code>&lt;#categoryID&gt;</code>. The mapping for categories, <samp>categories.rq</samp>:</p>\n    <pre>PREFIX foaf:       &lt;http://xmlns.com/foaf/0.1/&gt;\nPREFIX dct:        &lt;http://purl.org/dc/terms/&gt;\nPREFIX schema:     &lt;https://schema.org/&gt;\n\nCONSTRUCT\n{\n    GRAPH ?graph\n    {\n        ?graph dct:title ?categoryName ;\n            foaf:primaryTopic ?category .\n\n        ?category a schema:ProductGroup ;\n            dct:title ?categoryName ;\n            dct:description ?description ;\n            schema:name ?categoryName ;\n            schema:identifier ?categoryID ;\n            schema:description ?description ;\n            foaf:depiction ?picture .\n    }\n}\nWHERE\n{\n    ?category_row &lt;#categoryID&gt; ?categoryID ;\n        &lt;#description&gt; ?description ;\n        &lt;#categoryName&gt; ?categoryName ;\n        &lt;#pictureHash&gt; ?pictureHash .\n\n    BIND(uri(concat(str($base), \"categories/\")) AS ?container)\n    BIND(uri(concat(str(?container), encode_for_uri(?categoryID), \"/\")) AS ?graph)\n    BIND(uri(concat(str(?graph), \"#this\")) AS ?category)\n    BIND(uri(concat(str($base), \"uploads/\", encode_for_uri(?pictureHash))) AS ?picture)\n}</pre>\n    <p class=\"exhibit-links\">Source: <a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps/blob/master/demo/northwind-traders/categories/categories.rq\" target=\"_blank\">categories/categories.rq</a> · Live: <a href=\"https://northwind-traders.demo.linkeddatahub.com/categories/1/\" target=\"_blank\">/categories/1/</a></p>\n    <p>The four <code>BIND</code>s carry the whole document model of the import:</p>\n    <table>\n        <caption class=\"ac-vh\">BIND variables and what they bind to</caption>\n        <thead>\n            <tr>\n                <th scope=\"col\">Variable</th>\n                <th scope=\"col\">Binds to</th>\n            </tr>\n        </thead>\n        <tbody>\n            <tr>\n                <th scope=\"row\"><code>?container</code></th>\n                <td>The target container from the <a href=\"../structure/\">Structure</a> stage, resolved against <code>$base</code>, which LinkedDataHub binds to the dataspace's base URI when the mapping runs</td>\n            </tr>\n            <tr>\n                <th scope=\"row\"><code>?graph</code></th>\n                <td>One document (named graph) per row, minted inside the container from the row's identifier</td>\n            </tr>\n            <tr>\n                <th scope=\"row\"><code>?category</code></th>\n                <td>The document's topic: the document is <em>about</em> the category, so the category is a <samp>#this</samp> fragment of it</td>\n            </tr>\n            <tr>\n                <th scope=\"row\"><code>?picture</code></th>\n                <td>The category's image, addressed by the content hash the CSV carries (the <a href=\"../media/\">Media</a> stage explains why that works)</td>\n            </tr>\n        </tbody>\n    </table>\n    <div class=\"ac-tabs or-horizontal\">\n        <div class=\"ac-tablist sz-md va-line\" role=\"tablist\">\n            <button aria-controls=\"in-the-browser-pane\" aria-selected=\"true\" class=\"ac-tab is-on\" id=\"in-the-browser-tab\" role=\"tab\" type=\"button\"><span class=\"ac-tab-lbl\">In the browser</span></button>\n            <button aria-controls=\"from-the-command-line-pane\" aria-selected=\"false\" class=\"ac-tab\" id=\"from-the-command-line-tab\" role=\"tab\" type=\"button\"><span class=\"ac-tab-lbl\">From the command line</span></button>\n        </div>\n        <div aria-labelledby=\"in-the-browser-tab\" class=\"ac-tabpanel\" id=\"in-the-browser-pane\" role=\"tabpanel\">\n        <p>Upload the CSV file, save the mapping query as a <samp>CONSTRUCT</samp> document, then create a <samp>CSV Import</samp> that pairs the two with the target container — three passes through\n            the <span class=\"ac-btn in-primary ap-solid sz-md\">Create</span> dropdown, walked through step by step in the <a href=\"../../user-guide/import-data/import-csv-data/\" target=\"_blank\">Import CSV data</a>\n            guide.</p>\n        </div>\n        <div aria-labelledby=\"from-the-command-line-tab\" class=\"ac-tabpanel\" hidden=\"hidden\" id=\"from-the-command-line-pane\" role=\"tabpanel\">\n        <p>Each import pairs a mapping query with a CSV file and a target container. The demo lists them in a manifest, <samp>imports.csv</samp>:</p>\n        <pre>query_filename,csv_filename,target,title\ncategories/categories.rq,categories/categories.csv,categories/,Categories\ncustomers/customers.rq,customers/customers.csv,customers/,Customers\nemployees/employees.rq,employees/employees.csv,employees/,Employees\norders/orders.rq,orders/orders.csv,orders/,Orders\n...</pre>\n        <p class=\"exhibit-links\">Source: <a href=\"https://github.com/AtomGraph/LinkedDataHub-Apps/blob/master/demo/northwind-traders/imports.csv\" target=\"_blank\">imports.csv</a></p>\n        <p>A small loop over the <a href=\"../../reference/command-line-interface/\" target=\"_blank\">CLI</a> replays the manifest: each line saves its mapping query with\n            <samp>ldh add construct</samp>, then pairs it with the CSV file and target container in an import created with <samp>ldh add csv-import</samp>.</p>\n        <p>Upload the CSV first with <samp>ldh add file</samp>, which prints the upload URI the import refers to (the <a href=\"../media/\">Media</a> stage covers uploads). A single import\n            then looks like this:</p>\n        <pre>ldh add construct \\\n  --uri \"#categories-query\" \\\n  --title \"Categories\" \\\n  --query-file categories/categories.rq \\\n  \"${LDH_BASE}categories/\"\n\nldh add csv-import \\\n  --title \"Categories\" \\\n  --query \"${LDH_BASE}categories/#categories-query\" \\\n  --file \"$csv_upload_uri\" \\\n  \"${LDH_BASE}categories/\"</pre>\n        <p>(The readable <samp>#categories-query</samp> fragment is this tutorial's choice; the demo's <samp>install.sh</samp> mints a UUID fragment per query instead.)</p>\n        <p>Imports run asynchronously. Each import is itself a document that records its status — reload it to see progress, the amount of imported data on success, or the constraint\n            violations on failure.</p>\n        </div>\n    </div>\n    <div>\n        <h2 id=\"result\">What you now see</h2>\n        <p>The Categories container lists eight category documents. Open one: the category renders with its name, description and identifier, typed as a product group — with the labels coming from\n            the <a href=\"../model/\">Model</a> stage. Repeat the pattern for the remaining entities and the Knowledge Graph fills in: orders link to products, products to suppliers and\n            categories.</p>\n        <img alt=\"The Categories container listing after the import\" src=\"/uploads/db90ffc636cf6b4fc6a5e8d40f0fc3ca8f6b0046\"></img>\n    </div>\n    <div>\n        <h2 id=\"how-this-works\">How this works</h2>\n        <ul>\n            <li><a href=\"../../reference/imports/csv/\" target=\"_blank\">CSV imports</a> — the import pipeline: file, mapping query, import resource, validation</li>\n            <li><a href=\"../../reference/imports/#mapping-queries\" target=\"_blank\">Mapping queries</a> — the rules mapping queries follow, with an annotated skeleton</li>\n        </ul>\n    </div>\n    <p class=\"ldh-body-lg\">Next: <a href=\"../media/\">Media</a></p>\n</div>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral> .
