{"id":17102,"date":"2026-07-02T14:05:56","date_gmt":"2026-07-02T05:05:56","guid":{"rendered":"https:\/\/www.sambuichi.jp\/?p=17102"},"modified":"2026-07-02T16:59:02","modified_gmt":"2026-07-02T07:59:02","slug":"%e6%a7%8b%e6%96%87%e7%b5%90%e5%90%88%e8%a1%a8csv%e3%81%a7%e3%81%a4%e3%81%8f%e3%82%8b%e6%a7%8b%e9%80%a0%e5%8c%96csv%e3%81%a8jp-pint-ubl%e3%81%ae%e7%9b%b8%e4%ba%92%e5%a4%89%e6%8f%9b-2","status":"publish","type":"post","link":"https:\/\/www.sambuichi.jp\/?p=17102","title":{"rendered":"\u69cb\u6587\u7d50\u5408\u8868CSV\u3067\u5b9f\u73fe\u3059\u308b\u69cb\u9020\u5316CSV\u3068JP PINT UBL\u306e\u76f8\u4e92\u5909\u63db (Python)"},"content":{"rendered":"<p>Views: 2<\/p><div id=\"header\">\n<h1>\u69cb\u6587\u7d50\u5408\u8868CSV\u3067\u5b9f\u73fe\u3059\u308b\u69cb\u9020\u5316CSV\u3068JP PINT UBL\u306e\u76f8\u4e92\u5909\u63db<\/h1>\n<div class=\"details\"><span id=\"author\" class=\"author\">ChatGPT\uff08\u7de8\u96c6\u3000\u4e09\u5206\u4e00\u4fe1\u4e4b\uff09<\/span><br \/>\n<span id=\"revdate\">2026-07-02<\/span><\/div>\n<\/div>\n<div id=\"content\">\n<div class=\"sect1\">\n<h2 id=\"_\u306f\u3058\u3081\u306b\">1. \u306f\u3058\u3081\u306b<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u524d\u56de\u306e\u8a18\u4e8b\u3067\u306f\uff0c\u65e5\u672c\u7248\u30b3\u30a2\u30a4\u30f3\u30dc\u30a4\u30b9\u3092\u69cb\u9020\u5316CSV\u3068\u3057\u3066\u8868\u73fe\u3057\uff0cJP PINT UBL\u3068\u306e\u5bfe\u5fdc\u3092 SemanticPath \u3068 XPath \u306e\u69cb\u6587\u7d50\u5408\u8868\u3068\u3057\u3066\u6574\u7406\u3057\u305f\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u672c\u7a3f\u3067\u306f\uff0c\u305d\u306e\u69cb\u6587\u7d50\u5408\u8868\u3092\u4f7f\u3063\u3066\uff0c\u69cb\u9020\u5316CSV\u3068JP PINT UBL XML\u3092\u76f8\u4e92\u5909\u63db\u3059\u308bPython\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u8003\u3048\u65b9\u3092\u7d39\u4ecb\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4eca\u56de\u306e\u6539\u8a02\u3067\u306f\uff0c\u8aac\u660e\u7528\u306ePython\u30b3\u30fc\u30c9\u306b\u57cb\u3081\u8fbc\u3093\u3067\u3044\u305f\u8acb\u6c42\u66f8CSV\u53ca\u3073\u69cb\u6587\u7d50\u5408\u8868\u3092\uff0c\u5916\u90e8CSV\u30d5\u30a1\u30a4\u30eb\u3068\u3057\u3066\u8aad\u307f\u8fbc\u3080\u5f62\u306b\u5909\u66f4\u3057\u305f\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u3053\u3067\u793a\u3059\u30d7\u30ed\u30b0\u30e9\u30e0\u306f\uff0cJP PINT UBL \u306e\u5b8c\u5168\u306a\u5b9f\u88c5\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u4eca\u56de\u540c\u68b1\u3057\u3066\u3044\u308b <code>bindings.csv<\/code> \u3082\uff0c\u4ee3\u8868\u7684\u306a\u5b9a\u7fa9\u9805\u76ee\u306e\u629c\u7c8b\u3067\u3042\u308a\uff0cJP PINT \u304c\u5fc5\u9808\u3068\u3057\u3066\u3044\u308b\u9805\u76ee\u3092\u3059\u3079\u3066\u542b\u3093\u3067\u3044\u308b\u308f\u3051\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u76ee\u7684\u306f\uff0c\u6b21\u306e\u70b9\u3092\u30a4\u30e1\u30fc\u30b8\u3068\u3057\u3066\u3064\u304b\u3080\u3053\u3068\u3067\u3059\u3002<\/p>\n<\/div>\n<div class=\"ulist\">\n<ul>\n<li>CSV\u5074\u306e\u9805\u76ee\u3092 SemanticPath \u3067\u6307\u5b9a\u3059\u308b\u3002<\/li>\n<li>XML\u5074\u306e\u9805\u76ee\u3092 XPath \u3067\u6307\u5b9a\u3059\u308b\u3002<\/li>\n<li>\u69cb\u6587\u7d50\u5408\u8868\u3092 <code>bindings.csv<\/code> \u3068\u3057\u3066\u5916\u90e8\u5316\u3059\u308b\u3002<\/li>\n<li>\u30d7\u30ed\u30b0\u30e9\u30e0\u672c\u4f53\u306f\uff0c\u69cb\u6587\u7d50\u5408\u8868\u3092\u8aad\u307f\u53d6\u308a\uff0cCSV\u304b\u3089XML\u3092\u751f\u6210\u3059\u308b\u3002<\/li>\n<li>\u9006\u65b9\u5411\u3067\u306f\uff0cXML\u304b\u3089XPath\u3067\u5024\u3092\u53d6\u5f97\u3057\uff0c\u69cb\u9020\u5316CSV\u306e\u884c\u3078\u5c55\u958b\u3059\u308b\u3002<\/li>\n<li>\u5bfe\u5fdc\u5148\u306e\u69cb\u6587\u304c\u5909\u308f\u3063\u3066\u3082\uff0c\u539f\u5247\u3068\u3057\u3066\u7d50\u5408\u5b9a\u7fa9CSV\u3092\u5909\u66f4\u3059\u308c\u3070\uff0c\u540c\u3058\u6c4e\u7528\u30d7\u30ed\u30b0\u30e9\u30e0\u3092\u5229\u7528\u3067\u304d\u308b\u3002<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3064\u307e\u308a\uff0c\u5909\u63db\u30ed\u30b8\u30c3\u30af\u3092\u30d7\u30ed\u30b0\u30e9\u30e0\u5185\u306b\u76f4\u63a5\u66f8\u304d\u8fbc\u3080\u306e\u3067\u306f\u306a\u304f\uff0c\u69cb\u6587\u7d50\u5408\u8868\u3068\u3057\u3066\u5916\u90e8\u5316\u3059\u308b\u3053\u3068\u304c\u91cd\u8981\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u30d5\u30a1\u30a4\u30eb\u69cb\u6210\">2. \u30d5\u30a1\u30a4\u30eb\u69cb\u6210<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u4eca\u56de\u306e\u30b5\u30f3\u30d7\u30eb\u306f\uff0c\u6b21\u306e3\u30d5\u30a1\u30a4\u30eb\u3092\u4f7f\u3046\u3002<\/p>\n<div class=\"paragraph\">\n<p>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\uff1a<a href=\"https:\/\/www.sambuichi.jp\/wp-content\/uploads\/2026\/07\/syntax_binding_revised_package.zip\">syntax_binding_revised_package<\/a><\/p>\n<\/div>\n<\/div>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 25%;\" \/>\n<col style=\"width: 75%;\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">\u30d5\u30a1\u30a4\u30eb<\/th>\n<th class=\"tableblock halign-left valign-top\">\u5f79\u5272<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>invoice.csv<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u65e5\u672c\u7248\u30b3\u30a2\u30a4\u30f3\u30dc\u30a4\u30b9\u3092\u8868\u3059\u69cb\u9020\u5316CSV\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>bindings.csv<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u69cb\u9020\u5316CSV\u5074\u306e SemanticPath \u3068\uff0cJP PINT UBL\u5074\u306e XPath \u3092\u5bfe\u5fdc\u4ed8\u3051\u308b\u69cb\u6587\u7d50\u5408\u8868\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>syntax_binding.py<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u69cb\u9020\u5316CSV\u3068\u69cb\u6587\u7d50\u5408\u8868CSV\u3092\u8aad\u307f\u8fbc\u307f\uff0cJP PINT UBL XML\u3092\u751f\u6210\u3057\uff0c\u3055\u3089\u306bXML\u304b\u3089\u69cb\u9020\u5316CSV\u3078\u623b\u3059\u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0\u3002<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>PowerShell \u3067\u306e\u5b9f\u884c\u4f8b\u306f\u6b21\u306e\u3068\u304a\u308a\u3067\u3059\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-powershell\" data-lang=\"powershell\">py .\\syntax_binding.py .\\invoice.csv .\\bindings.csv `\r\n  --xml-out .\\invoice.xml `\r\n  --roundtrip-out .\\roundtrip.csv<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><code>py<\/code> \u304c\u4f7f\u3048\u306a\u3044\u74b0\u5883\u3067\u306f\uff0c<code>python<\/code> \u306b\u7f6e\u304d\u63db\u3048\u3066\u3082\u304b\u307e\u3044\u307e\u305b\u3093\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u5b9f\u884c\u306b\u3088\u308a\uff0c\u6b21\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u751f\u6210\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 25%;\" \/>\n<col style=\"width: 75%;\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">\u51fa\u529b\u30d5\u30a1\u30a4\u30eb<\/th>\n<th class=\"tableblock halign-left valign-top\">\u5185\u5bb9<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>invoice.xml<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u69cb\u9020\u5316CSV\u304b\u3089\u751f\u6210\u3057\u305fJP PINT UBL subset XML\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>roundtrip.csv<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u751f\u6210\u3057\u305fXML\u3092\u8aad\u307f\u623b\u3057\u3066\u518d\u69cb\u6210\u3057\u305f\u69cb\u9020\u5316CSV\u3002<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u69cb\u9020\u5316csv\u3068\u69cb\u6587\u7d50\u5408\u8868\">3. \u69cb\u9020\u5316CSV\u3068\u69cb\u6587\u7d50\u5408\u8868<\/h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"_\u69cb\u9020\u5316csv\u306e\u4f8b\">3.1. \u69cb\u9020\u5316CSV\u306e\u4f8b<\/h3>\n<div class=\"paragraph\">\n<p>\u672c\u7a3f\u3067\u306f\uff0c\u8acb\u6c42\u66f8\u69cb\u9020\u5316CSV\u3092\u4f8b\u306b\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-csv\" data-lang=\"csv\">dInvoice,dInvoiceParty,dDocumentReference,dPayment,dTaxBreakdown,dInvoiceLine,invoiceNumber,issueDate,invoiceTypeCode,currencyCode,totalAmount,totalTaxAmount,partyRole,partyName,partyTaxID,referenceType,referenceID,paymentDueDate,paymentMeansCode,paymentReference,taxCategoryCode,taxRate,taxableAmount,taxAmount,lineID,itemName,lineTaxCategoryCode,lineTaxRate,invoicedQuantity,unitCode,unitPriceAmount,lineExtensionAmount\r\n1,,,,,,INV-26-861,2026-06-20,380,JPY,16802,1472,,,,,,,,,,,,,,,,,,,,\r\n1,1,,,,,,,,,,,Seller,\u58f2\u624b\u682a\u5f0f\u4f1a\u793e,T1234567890123,,,,,,,,,,,,,,,,,\r\n1,2,,,,,,,,,,,Buyer,\u8cb7\u624b\u682a\u5f0f\u4f1a\u793e,,,,,,,,,,,,,,,,,,\r\n1,,1,,,,,,,,,,,,,Order,PO-2026-0001,,,,,,,,,,,,,,,\r\n1,,2,,,,,,,,,,,,,Delivery,DN-2026-0001,,,,,,,,,,,,,,,\r\n1,,,1,,,,,,,,,,,,,,2026-07-31,30,INV-2026-0001,,,,,,,,,,,,\r\n1,,,,1,,,,,,,,,,,,,,,,S,10,12320,1232,,,,,,,,\r\n1,,,,1,,,,,,,,,,,,,,,,AA,8,3010,240,,,,,,,,\r\n1,,,,,1,,,,,,,,,,,,,,,,,,,INV-26-861-1,\u5546\u54c1A,S,10,10,EA,1000,10000\r\n1,,,,,2,,,,,,,,,,,,,,,,,,,INV-26-861-2,\u5546\u54c1B,S,10,4,EA,580,2320\r\n1,,,,,3,,,,,,,,,,,,,,,,,,,INV-26-861-3,\u98df\u54c1C,AA,8,7,EA,430,3010<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306eCSV\u3067\u306f\uff0c\u8acb\u6c42\u66f8\u30d8\u30c3\u30c0\u30fc\uff0c\u58f2\u624b\uff0c\u8cb7\u624b\uff0c\u53c2\u7167\u6587\u66f8\uff0c\u652f\u6255\u60c5\u5831\uff0c\u7a0e\u7387\u5225\u5185\u8a33\uff0c\u8acb\u6c42\u660e\u7d30\u3092\uff0c1\u679a\u306eCSV\u306b\u683c\u7d0d\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u91cd\u8981\u306a\u306e\u306f\uff0c<code>dInvoiceParty<\/code>\uff0c<code>dDocumentReference<\/code>\uff0c<code>dPayment<\/code>\uff0c<code>dTaxBreakdown<\/code>\uff0c<code>dInvoiceLine<\/code> \u306a\u3069\u306e\u5217\u3067\u3042\u308b\u3002\u3053\u308c\u3089\u306f\uff0c\u884c\u304c\u3069\u306e\u968e\u5c64\u53c8\u306f\u7e70\u8fd4\u3057\u69cb\u9020\u306b\u5c5e\u3059\u308b\u304b\u3092\u793a\u3059\u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3\u5217\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4f8b\u3048\u3070\uff0c\u6b21\u306e\u884c\u306f\u58f2\u624b\u3092\u8868\u3059\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-csv\" data-lang=\"csv\">1,1,,,,,,,,,,,Seller,\u58f2\u624b\u682a\u5f0f\u4f1a\u793e,T1234567890123,,,,,,,,,,,,,,,,,<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u884c\u3067\u306f\uff0c<code>dInvoiceParty<\/code> \u306b <code>1<\/code> \u304c\u5165\u308a\uff0c<code>partyRole<\/code> \u306b <code>Seller<\/code> \u304c\u5165\u3063\u3066\u3044\u308b\u3002\u3057\u305f\u304c\u3063\u3066\uff0c\u3053\u306e\u884c\u306f\u300c\u8acb\u6c42\u66f8\u5f53\u4e8b\u8005\u306e\u3046\u3061\uff0c\u58f2\u624b\u3092\u8868\u3059\u884c\u300d\u3068\u89e3\u91c8\u3067\u304d\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u69cb\u6587\u7d50\u5408\u8868csv\">3.2. \u69cb\u6587\u7d50\u5408\u8868CSV<\/h3>\n<div class=\"paragraph\">\n<p>\u69cb\u6587\u7d50\u5408\u8868\u306f\uff0c\u69cb\u9020\u5316CSV\u5074\u306e SemanticPath \u3068\uff0cJP PINT UBL\u5074\u306e XPath \u3092\u5bfe\u5fdc\u4ed8\u3051\u308b\u8868\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4eca\u56de\u306e\u6539\u8a02\u3067\u306f\uff0c\u3053\u306e\u5bfe\u5fdc\u8868\u3092Python\u30b3\u30fc\u30c9\u4e2d\u306e <code>BINDINGS<\/code> \u30ea\u30b9\u30c8\u3067\u306f\u306a\u304f\uff0c\u6b21\u306e <code>bindings.csv<\/code> \u3068\u3057\u3066\u5916\u90e8\u5316\u3057\u305f\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-csv\" data-lang=\"csv\">semantic_path,xpath\r\n$.Invoice.invoiceNumber,\/Invoice\/cbc:ID\r\n$.Invoice.issueDate,\/Invoice\/cbc:IssueDate\r\n$.Invoice.invoiceTypeCode,\/Invoice\/cbc:InvoiceTypeCode\r\n$.Invoice.currencyCode,\/Invoice\/cbc:DocumentCurrencyCode\r\n$.Invoice.dInvoiceParty[?@.partyRole=Seller].partyName,\/Invoice\/cac:AccountingSupplierParty\/cac:Party\/cac:PartyName\/cbc:Name\r\n$.Invoice.dInvoiceParty[?@.partyRole=Seller].partyTaxID,\/Invoice\/cac:AccountingSupplierParty\/cac:Party\/cac:PartyTaxScheme\/cbc:CompanyID\r\n$.Invoice.dInvoiceParty[?@.partyRole=Buyer].partyName,\/Invoice\/cac:AccountingCustomerParty\/cac:Party\/cac:PartyName\/cbc:Name\r\n$.Invoice.dInvoiceParty[?@.partyRole=Buyer].partyTaxID,\/Invoice\/cac:AccountingCustomerParty\/cac:Party\/cac:PartyTaxScheme\/cbc:CompanyID\r\n$.Invoice.dDocumentReference[?@.referenceType=Order].referenceID,\/Invoice\/cac:OrderReference\/cbc:ID\r\n$.Invoice.dDocumentReference[?@.referenceType=Delivery].referenceID,\/Invoice\/cac:DespatchDocumentReference\/cbc:ID\r\n$.Invoice.paymentDueDate,\/Invoice\/cbc:DueDate\r\n$.Invoice.paymentReference,\/Invoice\/cac:PaymentMeans\/cbc:PaymentID\r\n$.Invoice.totalTaxAmount,\/Invoice\/cac:TaxTotal\/cbc:TaxAmount\r\n$.Invoice.currencyCode,\/Invoice\/cac:TaxTotal\/cbc:TaxAmount\/@currencyID\r\n$.Invoice.dTaxBreakdown.taxableAmount,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cbc:TaxableAmount\r\n$.Invoice.currencyCode,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cbc:TaxableAmount\/@currencyID\r\n$.Invoice.dTaxBreakdown.taxAmount,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cbc:TaxAmount\r\n$.Invoice.currencyCode,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cbc:TaxAmount\/@currencyID\r\n$.Invoice.dTaxBreakdown.taxCategoryCode,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cac:TaxCategory\/cbc:ID\r\n$.Invoice.dTaxBreakdown.taxRate,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cac:TaxCategory\/cbc:Percent\r\nconst:VAT,\/Invoice\/cac:TaxTotal\/cac:TaxSubtotal\/cac:TaxCategory\/cac:TaxScheme\/cbc:ID<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4f8b\u3048\u3070\uff0c\u58f2\u624b\u540d\u79f0\u306f\u6b21\u306e\u3088\u3046\u306b\u6307\u5b9a\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">$.Invoice.dInvoiceParty[?@.partyRole=Seller].partyName<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u308c\u306f\uff0c\u6b21\u306e\u610f\u5473\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre>dInvoiceParty \u306e\u884c\u306e\u3046\u3061\uff0c\r\npartyRole \u304c Seller \u3067\u3042\u308b\u884c\u3092\u9078\u629e\u3057\uff0c\r\n\u305d\u306e\u884c\u306e partyName \u3092\u53d6\u5f97\u3059\u308b\u3002<\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u305d\u306e\u5024\u3092\uff0c\u6b21\u306eXPath\u3067\u6307\u5b9a\u3055\u308c\u308bXML\u8981\u7d20\u3078\u8a2d\u5b9a\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">\/Invoice\/cac:AccountingSupplierParty\/cac:Party\/cac:PartyName\/cbc:Name<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u30d7\u30ed\u30b0\u30e9\u30e0\u306f\uff0cCSV\u5217\u540d\u3068XML\u8981\u7d20\u540d\u306e\u5bfe\u5fdc\u3092\u76f4\u63a5\u77e5\u3063\u3066\u3044\u308b\u306e\u3067\u306f\u306a\u3044\u3002\u5bfe\u5fdc\u95a2\u4fc2\u3092 <code>bindings.csv<\/code> \u304b\u3089\u8aad\u307f\u8fbc\u307f\uff0cSemanticPath \u3068 XPath \u3092\u4f7f\u3063\u3066\u51e6\u7406\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_bindings_csv_\u306e\u5b9a\u7fa9\u65b9\u6cd5\">3.3. bindings.csv \u306e\u5b9a\u7fa9\u65b9\u6cd5<\/h3>\n<div class=\"paragraph\">\n<p><code>bindings.csv<\/code> \u306f\uff0c\u5358\u306b\u300cCSV \u306e\u5217\u540d\u300d\u3068\u300cXML \u306e\u8981\u7d20\u540d\u300d\u3092\u5bfe\u5fdc\u4ed8\u3051\u308b\u3060\u3051\u306e\u8868\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u69cb\u9020\u5316CSV\u5074\u306e\u8ad6\u7406\u5b9a\u7fa9\u3068\uff0cXML\u5074\u306e\u69cb\u6587\u5b9a\u7fa9\u3092\u5bfe\u5fdc\u4ed8\u3051\u308b\u8868\u3067\u3059\u3002\u4eca\u56de\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u306f\uff0c\u4e3b\u306b\u6b21\u306e4\u7a2e\u985e\u306e\u8a18\u6cd5\u3092\u4f7f\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 30%;\" \/>\n<col style=\"width: 70%;\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">\u8a18\u6cd5<\/th>\n<th class=\"tableblock halign-left valign-top\">\u610f\u5473<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>$.Invoice.invoiceNumber<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u8acb\u6c42\u66f8\u5168\u4f53\u306b1\u56de\u3060\u3051\u73fe\u308c\u308b\u5358\u4e00\u9805\u76ee\u3067\u3059\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>$.Invoice.dInvoiceParty[?@.partyRole=Seller].partyName<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dInvoiceParty<\/code> \u306e\u884c\u306e\u3046\u3061\uff0c<code>partyRole=Seller<\/code> \u306e\u884c\u3092\u9078\u3073\uff0c\u305d\u306e <code>partyName<\/code> \u3092\u4f7f\u3046\u6761\u4ef6\u4ed8\u304d\u5b9a\u7fa9\u3067\u3059\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>$.Invoice.dTaxBreakdown.taxAmount<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dTaxBreakdown<\/code> \u306b\u5024\u304c\u3042\u308b\u5404\u884c\u3092\uff0c\u7a0e\u7387\u5225\u5185\u8a33\u306e\u7e70\u8fd4\u3057\u968e\u5c64\u3068\u3057\u3066\u6271\u3044\uff0c\u305d\u306e\u884c\u306e <code>taxAmount<\/code> \u3092\u4f7f\u3046\u5b9a\u7fa9\u3067\u3059\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>const:VAT<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">CSV \u304b\u3089\u5024\u3092\u8aad\u3080\u306e\u3067\u306f\u306a\u304f\uff0c\u56fa\u5b9a\u5024 <code>VAT<\/code> \u3092 XML \u306b\u66f8\u304d\u8fbc\u3080\u5b9a\u7fa9\u3067\u3059\u3002<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>\u56fa\u5b9a\u5024\u306e\u6307\u5b9a\u306f\uff0c\u5b9f\u52d9\u3067\u3082\u6709\u52b9\u306a\u8003\u3048\u65b9\u3067\u3059\u3002\u305f\u3068\u3048\u3070\uff0c<code>cac:TaxScheme\/cbc:ID<\/code> \u306e\u3088\u3046\u306b\uff0c\u5bfe\u8c61\u4ed5\u69d8\u4e0a\u306f\u5b9a\u6570\u3068\u3057\u3066\u6271\u3048\u308b\u5024\u3092\u6bce\u56de CSV \u306b\u6301\u305f\u305b\u308b\u5fc5\u8981\u304c\u306a\u3044\u5834\u5408\uff0c<code>const:<\/code> \u3092\u4f7f\u3046\u3068\u69cb\u6587\u7d50\u5408\u8868\u304c\u7c21\u6f54\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_dxxx_\u3068_cacxxx_cbczzz_\u306e\u5bfe\u5fdc\">3.4. dXXX \u3068 cac:XXX \/ cbc:ZZZ \u306e\u5bfe\u5fdc<\/h3>\n<div class=\"paragraph\">\n<p>\u69cb\u9020\u5316CSV\u3067\u306f\uff0c<code>dXXX<\/code> \u5217\u306b\u5024\u304c\u3042\u308b\u3053\u3068\u304c\uff0c\u305d\u306e\u884c\u304c\u3069\u306e\u7e70\u8fd4\u3057\u968e\u5c64\u306b\u5c5e\u3059\u308b\u304b\u3092\u793a\u3057\u307e\u3059\u3002\u305d\u3057\u3066\uff0c\u305d\u306e\u884c\u3067\u5024\u3092\u6301\u3064\u5404\u6b04\u306e\u30c7\u30fc\u30bf\u304c\uff0c\u305d\u306e\u968e\u5c64\u3067\u5b9a\u7fa9\u3055\u308c\u305f\u9805\u76ee\u3067\u3059\u3002\u3053\u308c\u304c\uff0c\u968e\u5c64\u69cb\u9020\u30921\u679a\u306eCSV\u3067\u8868\u3059\u69cb\u9020\u5316CSV\u306e\u57fa\u672c\u7684\u306a\u8003\u3048\u65b9\u3067\u3059\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>XML \u5074\u3067\u306f\uff0cCCTS \u306e Aggregate Business Information Entity\uff08ABIE\uff09\u306b\u5bfe\u5fdc\u3059\u308b\u96c6\u7d04\u7684\u306a\u696d\u52d9\u60c5\u5831\u8981\u7d20\u304c <code>cac:XXX<\/code> \u3067\u8868\u3055\u308c\uff0cBasic Business Information Entity\uff08BBIE\uff09\u306b\u5bfe\u5fdc\u3059\u308b\u57fa\u672c\u8981\u7d20\u304c <code>cbc:ZZZ<\/code> \u3067\u8868\u3055\u308c\u307e\u3059\u3002\u69cb\u9020\u5316CSV\u3067\u306f\uff0c\u3053\u306e ABIE \u306b\u5bfe\u5fdc\u3059\u308b\u8ad6\u7406\u968e\u5c64\u3092 <code>dYYY<\/code> \u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3\u3067\u8868\u3057\uff0c\u305d\u306e\u968e\u5c64\u306b\u5c5e\u3059\u308b BBIE \u76f8\u5f53\u306e\u9805\u76ee\u5024\u3092\u540c\u3058\u884c\u306e\u5217\u3068\u3057\u3066\u8a18\u8ff0\u3057\u307e\u3059\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u305f\u3068\u3048\u3070\u4eca\u56de\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u306f\uff0c\u6b21\u306e\u3088\u3046\u306a\u5bfe\u5fdc\u95a2\u4fc2\u3092\u60f3\u5b9a\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 35%;\" \/>\n<col style=\"width: 65%;\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">XML \u5074\u306e\u96c6\u7d04\u8981\u7d20<\/th>\n<th class=\"tableblock halign-left valign-top\">\u69cb\u9020\u5316CSV\u5074\u306e\u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:AccountingSupplierParty<\/code> \/ <code>cac:AccountingCustomerParty<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dInvoiceParty<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:OrderReference<\/code> \/ <code>cac:DespatchDocumentReference<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dDocumentReference<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:PaymentMeans<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dPayment<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:TaxSubtotal<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dTaxBreakdown<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:InvoiceLine<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dInvoiceLine<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u3088\u3046\u306b\u898b\u308b\u3068\uff0cXML \u5074\u306e <code>cac:XXX<\/code> \u306f\uff0c\u69cb\u9020\u5316CSV\u3067\u306f <code>dYYY<\/code> \u306b\u3088\u3063\u3066\u8868\u3055\u308c\u308b\u8ad6\u7406\u968e\u5c64\u306e\u69cb\u6587\u8868\u73fe\u3060\u3068\u7406\u89e3\u3067\u304d\u307e\u3059\u3002<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_python\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5168\u4f53\u69cb\u6210\">4. Python\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5168\u4f53\u69cb\u6210<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0\u306f\uff0c\u5927\u304d\u304f\u6b21\u306e\u51e6\u7406\u306b\u5206\u3051\u3089\u308c\u308b\u3002<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 30%;\" \/>\n<col style=\"width: 70%;\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">\u51e6\u7406<\/th>\n<th class=\"tableblock halign-left valign-top\">\u5f79\u5272<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">CSV\u8aad\u8fbc\u307f<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>invoice.csv<\/code> \u3092 <code>csv.DictReader<\/code> \u3067\u884c\u30ea\u30b9\u30c8\u3068\u3057\u3066\u8aad\u307f\u8fbc\u3080\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u69cb\u6587\u7d50\u5408\u8868\u8aad\u8fbc\u307f<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>bindings.csv<\/code> \u304b\u3089 SemanticPath \u3068 XPath \u306e\u5bfe\u5fdc\u3092\u8aad\u307f\u8fbc\u3080\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">SemanticPath\u8a55\u4fa1<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">CSV\u884c\u30ea\u30b9\u30c8\u304b\u3089\uff0c\u6307\u5b9a\u3055\u308c\u305f SemanticPath \u306b\u5bfe\u5fdc\u3059\u308b\u5024\u3092\u53d6\u5f97\u3059\u308b\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">XML\u751f\u6210<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">XPath\u306b\u5f93\u3063\u3066XML\u8981\u7d20\u3092\u4f5c\u6210\u3057\uff0c\u53d6\u5f97\u3057\u305f\u5024\u3092\u8a2d\u5b9a\u3059\u308b\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">XML\u8aad\u8fbc\u307f<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">ElementTree\u3067XML\u3092\u8aad\u307f\u8fbc\u307f\uff0cXPath\u76f8\u5f53\u306e\u30d1\u30b9\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b\u3002<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">CSV\u751f\u6210<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">XML\u304b\u3089\u53d6\u5f97\u3057\u305f\u5024\u3092\uff0c\u69cb\u9020\u5316CSV\u306e\u884c\u3068\u3057\u3066\u518d\u69cb\u6210\u3059\u308b\u3002<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>\u672c\u7a3f\u3067\u306f\uff0cPython\u6a19\u6e96\u30e9\u30a4\u30d6\u30e9\u30ea\u306e <code>csv<\/code> \u3068 <code>xml.etree.ElementTree<\/code> \u3092\u4f7f\u7528\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_csv\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3080\">4.1. CSV\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3080<\/h3>\n<div class=\"paragraph\">\n<p>\u69cb\u9020\u5316CSV\u306f\uff0cPython\u306e\u6a19\u6e96\u30e9\u30a4\u30d6\u30e9\u30ea <code>csv<\/code> \u3067\u8aad\u307f\u8fbc\u3080\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">from __future__ import annotations\r\n\r\nimport argparse\r\nimport csv\r\nimport io\r\nimport re\r\nimport xml.etree.ElementTree as ET\r\nfrom pathlib import Path\r\n\r\ndef read_core_csv(text: str) -&gt; list[dict[str, str]]:\r\n    \"\"\"\u69cb\u9020\u5316CSV\u6587\u5b57\u5217\u3092\u30011\u884c1\u8f9e\u66f8\u306e\u30ea\u30b9\u30c8\u3078\u5909\u63db\u3057\u307e\u3059\u3002\"\"\"\r\n    return list(csv.DictReader(io.StringIO(text)))\r\n\r\n\r\ndef read_core_csv_file(path: str | Path, encoding: str = \"utf-8-sig\") -&gt; list[dict[str, str]]:\r\n    \"\"\"\u69cb\u9020\u5316CSV\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u307e\u3059\u3002Excel \u4fdd\u5b58\u6642\u306e BOM \u306b\u3082\u5bfe\u5fdc\u3059\u308b\u305f\u3081 utf-8-sig \u3092\u4f7f\u3044\u307e\u3059\u3002\"\"\"\r\n    return read_core_csv(Path(path).read_text(encoding=encoding))<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><code>read_core_csv_file()<\/code> \u306f\uff0c<code>invoice.csv<\/code> \u3092\u8aad\u307f\u8fbc\u307f\uff0c1\u884c\u30921\u3064\u306e\u8f9e\u66f8\u3068\u3057\u3066\u6271\u3048\u308b\u3088\u3046\u306b\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">[\r\n    {\r\n        \"dInvoice\": \"1\",\r\n        \"invoiceNumber\": \"INV-26-861\",\r\n        \"issueDate\": \"2026-06-20\",\r\n    },\r\n    {\r\n        \"dInvoice\": \"1\",\r\n        \"dInvoiceParty\": \"1\",\r\n        \"partyRole\": \"Seller\",\r\n        \"partyName\": \"\u58f2\u624b\u682a\u5f0f\u4f1a\u793e\",\r\n        \"partyTaxID\": \"T1234567890123\",\r\n    },\r\n]<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>1\u884c\u304c1\u3064\u306e\u8f9e\u66f8\u306b\u306a\u308a\uff0cCSV\u306e\u5217\u540d\u3092\u30ad\u30fc\u3068\u3057\u3066\u5024\u3092\u53d6\u5f97\u3067\u304d\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u69cb\u6587\u7d50\u5408\u8868csv\u3092\u8aad\u307f\u8fbc\u3080\">4.2. \u69cb\u6587\u7d50\u5408\u8868CSV\u3092\u8aad\u307f\u8fbc\u3080<\/h3>\n<div class=\"paragraph\">\n<p><code>bindings.csv<\/code> \u306f\uff0c<code>semantic_path<\/code> \u3068 <code>xpath<\/code> \u306e2\u5217\u3092\u6301\u3064CSV\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def read_bindings_csv(text: str) -&gt; list[Binding]:\r\n    \"\"\"bindings.csv \u3092\u8aad\u307f\u8fbc\u307f\u3001(semantic_path, xpath) \u306e\u30ea\u30b9\u30c8\u3078\u5909\u63db\u3057\u307e\u3059\u3002\"\"\"\r\n    bindings: list[Binding] = []\r\n    reader = csv.DictReader(io.StringIO(text))\r\n    if reader.fieldnames is None:\r\n        raise ValueError(\"Binding CSV has no header\")\r\n\r\n    fieldnames = [name.lstrip(\"\\ufeff\") for name in reader.fieldnames]\r\n    if \"semantic_path\" not in fieldnames or \"xpath\" not in fieldnames:\r\n        raise ValueError(\"Binding CSV must have semantic_path and xpath columns\")\r\n\r\n    for line_no, row in enumerate(reader, start=2):\r\n        normalized = {k.lstrip(\"\\ufeff\"): (v or \"\").strip() for k, v in row.items()}\r\n        semantic_path = normalized.get(\"semantic_path\", \"\")\r\n        xpath = normalized.get(\"xpath\", \"\")\r\n        if not semantic_path and not xpath:\r\n            continue\r\n        if not semantic_path or not xpath:\r\n            raise ValueError(f\"Incomplete binding at line {line_no}: {row!r}\")\r\n        if not xpath.startswith(\"\/Invoice\/\") and xpath != \"\/Invoice\":\r\n            raise ValueError(f\"XPath must start with \/Invoice at line {line_no}: {xpath!r}\")\r\n        bindings.append((semantic_path, xpath))\r\n    return bindings\r\n\r\n\r\ndef read_bindings_csv_file(path: str | Path, encoding: str = \"utf-8-sig\") -&gt; list[Binding]:\r\n    return read_bindings_csv(Path(path).read_text(encoding=encoding))<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u95a2\u6570\u306b\u3088\u308a\uff0c\u69cb\u6587\u7d50\u5408\u8868\u306f\u6b21\u306e\u3088\u3046\u306a\u30bf\u30d7\u30eb\u306e\u30ea\u30b9\u30c8\u306b\u306a\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">[\r\n    (\"$.Invoice.invoiceNumber\", \"\/Invoice\/cbc:ID\"),\r\n    (\"$.Invoice.dInvoiceParty[?@.partyRole=Seller].partyName\",\r\n     \"\/Invoice\/cac:AccountingSupplierParty\/cac:Party\/cac:PartyName\/cbc:Name\"),\r\n]<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u3053\u3067\u91cd\u8981\u306a\u306e\u306f\uff0c\u5bfe\u5fdc\u95a2\u4fc2\u304c\u30d7\u30ed\u30b0\u30e9\u30e0\u5b9a\u6570\u3067\u306f\u306a\u304f\uff0c\u5916\u90e8\u30d5\u30a1\u30a4\u30eb\u3068\u3057\u3066\u5dee\u3057\u66ff\u3048\u53ef\u80fd\u306b\u306a\u3063\u3066\u3044\u308b\u3053\u3068\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_semanticpath\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b\">4.3. SemanticPath\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b<\/h3>\n<div class=\"paragraph\">\n<p>\u672c\u7a3f\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u306f\uff0c\u6b21\u306e2\u7a2e\u985e\u306eSemanticPath\u3060\u3051\u3092\u6271\u3046\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">$.Invoice.field\r\n$.Invoice.dimension[?@.filterField=filterValue].field<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4f8b\u3048\u3070\uff0c\u8acb\u6c42\u66f8\u756a\u53f7\u306f\u6b21\u306e\u5f62\u5f0f\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">$.Invoice.invoiceNumber<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u58f2\u624b\u540d\u79f0\u306f\u6b21\u306e\u5f62\u5f0f\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">$.Invoice.dInvoiceParty[?@.partyRole=Seller].partyName<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u308c\u3092\u51e6\u7406\u3059\u308b\u95a2\u6570\u306f\uff0c\u6b21\u306e\u3068\u304a\u308a\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def rows_by_dimension(rows: list[dict[str, str]], dimension: str, d_invoice: str = \"1\") -&gt; list[dict[str, str]]:\r\n    \"\"\"dXXX \u306b\u5024\u304c\u3042\u308b\u884c\u3060\u3051\u3092\u96c6\u3081\u3001\u305d\u306e\u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3\u968e\u5c64\u306e\u884c\u96c6\u5408\u3092\u8fd4\u3057\u307e\u3059\u3002\"\"\"\r\n    return [r for r in rows if r.get(\"dInvoice\") == d_invoice and r.get(dimension)]\r\n\r\n\r\ndef first_value(rows: list[dict[str, str]], column: str, d_invoice: str = \"1\") -&gt; str:\r\n    for row in rows:\r\n        if row.get(\"dInvoice\") == d_invoice and row.get(column):\r\n            return row[column]\r\n    return \"\"\r\n\r\n\r\ndef direct_dimension_target(path: str) -&gt; tuple[str, str] | None:\r\n    \"\"\"$.Invoice.dTaxBreakdown.taxAmount \u306e\u3088\u3046\u306a\u3001dXXX \u76f4\u4e0b\u306e\u9805\u76ee\u5b9a\u7fa9\u3092\u5224\u5b9a\u3057\u307e\u3059\u3002\"\"\"\r\n    m = re.fullmatch(r\"\\$\\.Invoice\\.(d[A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z_][A-Za-z0-9_]*)\", path)\r\n    if not m:\r\n        return None\r\n    return m.group(1), m.group(2)\r\n\r\n\r\ndef query_semantic_path(\r\n    rows: list[dict[str, str]],\r\n    path: str,\r\n    d_invoice: str = \"1\",\r\n    current_row: dict[str, str] | None = None,\r\n) -&gt; str:\r\n    \"\"\"\r\n    \u6271\u3046 SemanticPath subset:\r\n      const:VALUE\r\n      $.Invoice.field\r\n      $.Invoice.dDimension.field\r\n      $.Invoice.dimension[?@.filterField=\"filterValue\"].field\r\n      $.Invoice.dimension[?@.filterField=filterValue].field\r\n    \"\"\"\r\n    if path.startswith(\"const:\"):\r\n        return path.split(\":\", 1)[1]\r\n\r\n    m = re.fullmatch(r\"\\$\\.Invoice\\.([A-Za-z_][A-Za-z0-9_]*)\", path)\r\n    if m:\r\n        return first_value(rows, m.group(1), d_invoice)\r\n\r\n    dim_target = direct_dimension_target(path)\r\n    if dim_target:\r\n        dimension, target_field = dim_target\r\n        if current_row is not None and current_row.get(dimension):\r\n            return current_row.get(target_field, \"\")\r\n        repeated_rows = rows_by_dimension(rows, dimension, d_invoice)\r\n        if repeated_rows:\r\n            return repeated_rows[0].get(target_field, \"\")\r\n        return \"\"\r\n\r\n    m = re.fullmatch(\r\n        r\"\\$\\.Invoice\\.([A-Za-z_][A-Za-z0-9_]*)\"\r\n        r\"\\[\\?@\\.([A-Za-z_][A-Za-z0-9_]*)=(?:\\\"([^\\\"]+)\\\"|([^\\]]+))\\]\"\r\n        r\"\\.([A-Za-z_][A-Za-z0-9_]*)\",\r\n        path,\r\n    )\r\n    if m:\r\n        dimension, filter_field, quoted_value, bare_value, target_field = m.groups()\r\n        filter_value = quoted_value if quoted_value is not None else bare_value\r\n        for row in rows_by_dimension(rows, dimension, d_invoice):\r\n            if row.get(filter_field) == filter_value:\r\n                return row.get(target_field, \"\")\r\n        return \"\"\r\n\r\n    raise ValueError(f\"Unsupported SemanticPath: {path}\")<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u95a2\u6570\u306f\uff0c\u6c4e\u7528XPath\u3084\u6c4e\u7528JSONPath\u3092\u5b9f\u88c5\u3057\u3066\u3044\u308b\u308f\u3051\u3067\u306f\u306a\u3044\u3002\u69cb\u6587\u7d50\u5408\u8868\u3067\u5fc5\u8981\u3068\u306a\u308b\u6700\u5c0f\u9650\u306e SemanticPath subset \u3092\u5b9f\u88c5\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u5b9f\u52d9\u4e0a\u3082\uff0c\u6700\u521d\u304b\u3089\u3059\u3079\u3066\u306e\u5f0f\u3092\u8a31\u5bb9\u3059\u308b\u3088\u308a\uff0c\u69cb\u6587\u7d50\u5408\u8868\u3067\u4f7f\u7528\u3067\u304d\u308b\u8a18\u6cd5\u3092\u9650\u5b9a\u3057\u305f\u65b9\u304c\u5b89\u5168\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_elementtree\u3067xml\u3092\u6271\u3046\">4.4. ElementTree\u3067XML\u3092\u6271\u3046<\/h3>\n<div class=\"paragraph\">\n<p>JP PINT UBL\u306fXML\u540d\u524d\u7a7a\u9593\u3092\u4f7f\u7528\u3059\u308b\u3002ElementTree\u3067\u540d\u524d\u7a7a\u9593\u4ed8\u304dXML\u3092\u6271\u3046\u305f\u3081\uff0c\u307e\u305a\u540d\u524d\u7a7a\u9593\u3092\u5b9a\u7fa9\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">UBL_NS = \"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"\r\nCBC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\"\r\nCAC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\"\r\n\r\nNS = {\r\n    \"\": UBL_NS,\r\n    \"cbc\": CBC_NS,\r\n    \"cac\": CAC_NS,\r\n}\r\n\r\n# XML \u51fa\u529b\u6642\u306b\u898b\u3084\u3059\u3044\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u4ed8\u304d\u3067\u540d\u524d\u7a7a\u9593\u3092\u767b\u9332\u3059\u308b\r\nfor prefix, uri in NS.items():\r\n    ET.register_namespace(prefix, uri)\r\n\r\n\r\ndef qname(name: str) -&gt; str:\r\n    \"\"\"cbc:ID \u306e\u3088\u3046\u306a\u540d\u524d\u3092 ElementTree \u7528\u306e QName \u3078\u5909\u63db\u3057\u307e\u3059\u3002\"\"\"\r\n    if \":\" in name:\r\n        prefix, local = name.split(\":\", 1)\r\n        return f\"{{{NS[prefix]}}}{local}\"\r\n    return f\"{{{UBL_NS}}}{name}\"<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>ElementTree\u3067\u306f\uff0c\u540d\u524d\u7a7a\u9593\u4ed8\u304d\u8981\u7d20\u3092\u6b21\u306e\u5f62\u5f0f\u3067\u6307\u5b9a\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">{\u540d\u524d\u7a7a\u9593URI}\u30ed\u30fc\u30ab\u30eb\u540d<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4f8b\u3048\u3070\uff0c<code>cbc:ID<\/code> \u306f\u5185\u90e8\u7684\u306b\u306f\u6b21\u306e\u540d\u524d\u306b\u306a\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}ID<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u6bce\u56de\u3053\u306e\u6587\u5b57\u5217\u3092\u66f8\u304f\u306e\u306f\u7169\u96d1\u306a\u306e\u3067\uff0c\u63a5\u982d\u8f9e\u4ed8\u304d\u306e\u540d\u524d\u304b\u3089ElementTree\u7528\u306e\u540d\u524d\u3078\u5909\u63db\u3059\u308b\u95a2\u6570 <code>qname()<\/code> \u3092\u7528\u610f\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_xpath\u306b\u6cbf\u3063\u3066\u8981\u7d20\u3092\u751f\u6210\u3059\u308b\">4.5. XPath\u306b\u6cbf\u3063\u3066\u8981\u7d20\u3092\u751f\u6210\u3059\u308b<\/h3>\n<div class=\"paragraph\">\n<p>\u69cb\u6587\u7d50\u5408\u8868\u306b\u306f\uff0c\u6b21\u306e\u3088\u3046\u306aXPath\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">\/Invoice\/cac:AccountingSupplierParty\/cac:Party\/cac:PartyName\/cbc:Name<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u30d1\u30b9\u306b\u6cbf\u3063\u3066\uff0cInvoice\u306b\u8ffd\u52a0\u3059\u3079\u304d\u8981\u7d20\u3092\u9806\u756a\u306b\u4f5c\u6210\u3059\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def normalize_xpath(xpath: str) -&gt; str:\r\n    \"\"\"XPath \u6587\u5b57\u5217\u306e\u524d\u5f8c\u7a7a\u767d\u3092\u9664\u304d\u3001\u9014\u4e2d\u306b\u7a7a\u767d\u304c\u5165\u3063\u3066\u3044\u306a\u3044\u3053\u3068\u3092\u78ba\u8a8d\u3057\u307e\u3059\u3002\"\"\"\r\n    xpath = xpath.strip()\r\n    if re.search(r\"\\s\", xpath):\r\n        raise ValueError(f\"XPath contains whitespace: {xpath!r}\")\r\n    return xpath\r\n\r\n\r\ndef split_attr_path(xpath: str) -&gt; tuple[str, str | None]:\r\n    xpath = normalize_xpath(xpath)\r\n    if \"\/@\" in xpath:\r\n        elem_path, attr_name = xpath.rsplit(\"\/@\", 1)\r\n        return elem_path, attr_name\r\n    return xpath, None\r\n\r\n\r\ndef path_parts(xpath: str) -&gt; list[str]:\r\n    elem_path, _ = split_attr_path(xpath)\r\n    return [p for p in elem_path.split(\"\/\") if p]\r\n\r\n\r\ndef ensure_path(root: ET.Element, xpath: str) -&gt; ET.Element:\r\n    elem_path, _ = split_attr_path(xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    if not parts or parts[0] != \"Invoice\":\r\n        raise ValueError(f\"XPath must start with \/Invoice: {xpath}\")\r\n\r\n    elem = root\r\n    for part in parts[1:]:\r\n        tag = qname(part)\r\n        child = elem.find(tag)\r\n        if child is None:\r\n            child = ET.SubElement(elem, tag)\r\n        elem = child\r\n    return elem\r\n\r\n\r\ndef ensure_relative_path(root: ET.Element, rel_xpath: str) -&gt; ET.Element:\r\n    elem_path, _ = split_attr_path(rel_xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    elem = root\r\n    for part in parts:\r\n        tag = qname(part)\r\n        child = elem.find(tag)\r\n        if child is None:\r\n            child = ET.SubElement(elem, tag)\r\n        elem = child\r\n    return elem\r\n\r\n\r\ndef set_text(root: ET.Element, xpath: str, value: str | None) -&gt; None:\r\n    if value in (None, \"\"):\r\n        return\r\n    elem_path, attr_name = split_attr_path(xpath)\r\n    elem = ensure_path(root, elem_path)\r\n    if attr_name:\r\n        elem.set(attr_name, str(value))\r\n    else:\r\n        elem.text = str(value)\r\n\r\n\r\ndef set_text_relative(root: ET.Element, rel_xpath: str, value: str | None) -&gt; None:\r\n    if value in (None, \"\"):\r\n        return\r\n    elem_path, attr_name = split_attr_path(rel_xpath)\r\n    elem = ensure_relative_path(root, elem_path)\r\n    if attr_name:\r\n        elem.set(attr_name, str(value))\r\n    else:\r\n        elem.text = str(value)\r\n\r\n\r\ndef get_text(root: ET.Element, xpath: str) -&gt; str:\r\n    elem_path, attr_name = split_attr_path(xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    if not parts or parts[0] != \"Invoice\":\r\n        raise ValueError(f\"XPath must start with \/Invoice: {xpath}\")\r\n    elem = root\r\n    for part in parts[1:]:\r\n        elem = elem.find(qname(part))\r\n        if elem is None:\r\n            return \"\"\r\n    if attr_name:\r\n        return elem.attrib.get(attr_name, \"\")\r\n    return elem.text or \"\"\r\n\r\n\r\ndef get_text_relative(root: ET.Element, rel_xpath: str) -&gt; str:\r\n    elem_path, attr_name = split_attr_path(rel_xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    elem = root\r\n    for part in parts:\r\n        elem = elem.find(qname(part))\r\n        if elem is None:\r\n            return \"\"\r\n    if attr_name:\r\n        return elem.attrib.get(attr_name, \"\")\r\n    return elem.text or \"\"<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p><code>ensure_path()<\/code> \u306f\uff0c\u6307\u5b9a\u3055\u308c\u305fXPath\u306e\u6700\u5f8c\u306e\u8981\u7d20\u3092\u8fd4\u3059\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4f8b\u3048\u3070\uff0c\u6b21\u306e\u547c\u3073\u51fa\u3057\u3092\u884c\u3046\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">elem = ensure_path(\r\n    invoice,\r\n    \"\/Invoice\/cac:AccountingSupplierParty\/cac:Party\/cac:PartyName\/cbc:Name\"\r\n)\r\nelem.text = \"\u58f2\u624b\u682a\u5f0f\u4f1a\u793e\"<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u308c\u306b\u3088\u308a\uff0c\u6b21\u306e\u3088\u3046\u306aXML\u8981\u7d20\u304c\u751f\u6210\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-xml\" data-lang=\"xml\">&lt;cac:AccountingSupplierParty&gt;\r\n  &lt;cac:Party&gt;\r\n    &lt;cac:PartyName&gt;\r\n      &lt;cbc:Name&gt;\u58f2\u624b\u682a\u5f0f\u4f1a\u793e&lt;\/cbc:Name&gt;\r\n    &lt;\/cac:PartyName&gt;\r\n  &lt;\/cac:Party&gt;\r\n&lt;\/cac:AccountingSupplierParty&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u69cb\u6587\u7d50\u5408\u8868\u3092\u4f7f\u3063\u3066csv\u304b\u3089xml\u3092\u4f5c\u308b\">4.6. \u69cb\u6587\u7d50\u5408\u8868\u3092\u4f7f\u3063\u3066CSV\u304b\u3089XML\u3092\u4f5c\u308b<\/h3>\n<div class=\"paragraph\">\n<p>CSV\u304b\u3089XML\u3078\u306e\u5909\u63db\u306f\uff0c\u5358\u7d14\u9805\u76ee\u306b\u3064\u3044\u3066\u306f\u6b21\u306e3\u6bb5\u968e\u3067\u51e6\u7406\u3067\u304d\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre>1. SemanticPath\u3067CSV\u304b\u3089\u5024\u3092\u53d6\u5f97\u3059\u308b\u3002\r\n2. XPath\u3067XML\u4e0a\u306e\u8a2d\u5b9a\u5148\u3092\u6c7a\u3081\u308b\u3002\r\n3. \u53d6\u5f97\u3057\u305f\u5024\u3092XML\u8981\u7d20\u306b\u8a2d\u5b9a\u3059\u308b\u3002<\/pre>\n<\/div>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def csv_to_ubl_xml(rows: list[dict[str, str]], bindings: list[Binding], d_invoice: str = \"1\") -&gt; ET.Element:\r\n    \"\"\"\u69cb\u9020\u5316CSV\u3092 XML \u3078\u5909\u63db\u3057\u307e\u3059\u3002\u5358\u4e00\u9805\u76ee\u306f binding \u3067\u3001\u660e\u7d30\u884c\u306f\u88dc\u52a9\u51e6\u7406\u3067\u51fa\u529b\u3057\u307e\u3059\u3002\"\"\"\r\n    invoice = ET.Element(qname(\"Invoice\"))\r\n    # binding \u5b9a\u7fa9\u3092\u898b\u3066\u3001dXXX \u306b\u5bfe\u5fdc\u3059\u308b XML \u306e\u53cd\u5fa9\u968e\u5c64\u3092\u7279\u5b9a\u3059\u308b\r\n    repeat_defs = infer_repeat_definitions(bindings)\r\n\r\n    for semantic_path, xpath in scalar_bindings(bindings, repeat_defs):\r\n        value = query_semantic_path(rows, semantic_path, d_invoice)\r\n        set_text(invoice, xpath, value)\r\n\r\n    for dimension, repeat_path in repeat_defs.items():\r\n        apply_repeating_section(invoice, rows, bindings, dimension, repeat_path, d_invoice)\r\n\r\n    # \u660e\u7d30\u884c\u306f\u3053\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u306f\u88dc\u52a9\u51e6\u7406\u3067\u51fa\u529b\u3057\u3066\u3044\u308b\r\n    append_invoice_lines(invoice, rows, first_value(rows, \"currencyCode\", d_invoice), d_invoice)\r\n    return invoice<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u51e6\u7406\u3067\u306f\uff0c\u30d7\u30ed\u30b0\u30e9\u30e0\u672c\u4f53\u306f\u300c\u58f2\u624b\u306f\u3053\u306eXML\u8981\u7d20\u306b\u5165\u308c\u308b\u300d\u300c\u8cb7\u624b\u306f\u3053\u306eXML\u8981\u7d20\u306b\u5165\u308c\u308b\u300d\u3068\u3044\u3063\u305f\u696d\u52d9\u56fa\u6709\u306e\u5bfe\u5fdc\u3092\u77e5\u3089\u306a\u3044\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u5bfe\u5fdc\u95a2\u4fc2\u306f <code>bindings.csv<\/code> \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u308b\u3002\u3057\u305f\u304c\u3063\u3066\uff0c\u5225\u306eXML\u69cb\u6587\u3078\u5909\u63db\u3057\u305f\u3044\u5834\u5408\u3067\u3082\uff0c\u57fa\u672c\u7684\u306b\u306f <code>bindings.csv<\/code> \u3092\u5dee\u3057\u66ff\u3048\u308c\u3070\u3088\u3044\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u7e70\u8fd4\u3057\u69cb\u9020\u306e\u6271\u3044\">4.7. \u7e70\u8fd4\u3057\u69cb\u9020\u306e\u6271\u3044<\/h3>\n<div class=\"paragraph\">\n<p>\u8acb\u6c42\u66f8\u756a\u53f7\u3084\u767a\u884c\u65e5\u306f\uff0c1\u3064\u306e\u8acb\u6c42\u66f8\u306b1\u56de\u3060\u3051\u73fe\u308c\u308b\u9805\u76ee\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4e00\u65b9\uff0c\u7a0e\u7387\u5225\u5185\u8a33\u3084\u8acb\u6c42\u660e\u7d30\u306f\u7e70\u8fd4\u3057\u69cb\u9020\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<table class=\"tableblock frame-all grid-all stretch\">\n<colgroup>\n<col style=\"width: 30%;\" \/>\n<col style=\"width: 30%;\" \/>\n<col style=\"width: 40%;\" \/> <\/colgroup>\n<thead>\n<tr>\n<th class=\"tableblock halign-left valign-top\">\u69cb\u9020<\/th>\n<th class=\"tableblock halign-left valign-top\">CSV\u5074<\/th>\n<th class=\"tableblock halign-left valign-top\">XML\u5074<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u8acb\u6c42\u66f8\u30d8\u30c3\u30c0\u30fc<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>invoiceNumber<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cbc:ID<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u5f53\u4e8b\u8005<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dInvoiceParty<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:AccountingSupplierParty<\/code> \u7b49<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u7a0e\u7387\u5225\u5185\u8a33<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dTaxBreakdown<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:TaxSubtotal<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\">\u8acb\u6c42\u660e\u7d30<\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>dInvoiceLine<\/code><\/p>\n<\/td>\n<td class=\"tableblock halign-left valign-top\">\n<p class=\"tableblock\"><code>cac:InvoiceLine<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u305f\u3081\uff0c\u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u306f\uff0c\u5358\u7d14\u9805\u76ee\u306f <code>bindings.csv<\/code> \u3067\u51e6\u7406\u3057\uff0c<code>dTaxBreakdown<\/code> \u3068 <code>dInvoiceLine<\/code> \u306f\u7e70\u8fd4\u3057\u751f\u6210\u898f\u5247\u3068\u3057\u3066\u51e6\u7406\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u7a0e\u7387\u5225\u5185\u8a33\u3092xml\u3078\u5909\u63db\u3059\u308b\">4.8. \u7a0e\u7387\u5225\u5185\u8a33\u3092XML\u3078\u5909\u63db\u3059\u308b<\/h3>\n<div class=\"paragraph\">\n<p>\u69cb\u9020\u5316CSV\u3067\u306f\uff0c\u7a0e\u7387\u5225\u5185\u8a33\u306f <code>dTaxBreakdown<\/code> \u306b\u5024\u304c\u3042\u308b\u884c\u3068\u3057\u3066\u8868\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def apply_repeating_section(\r\n    invoice: ET.Element,\r\n    rows: list[dict[str, str]],\r\n    bindings: list[Binding],\r\n    dimension: str,\r\n    repeat_path: str,\r\n    d_invoice: str = \"1\",\r\n) -&gt; None:\r\n    # \u540c\u3058\u7e70\u8fd4\u3057\u968e\u5c64\u306b\u5c5e\u3059\u308b binding \u7fa4\u3092\u96c6\u3081\u308b\r\n    section_bindings = bindings_for_repeat_path(bindings, repeat_path)\r\n    if not section_bindings:\r\n        return\r\n\r\n    repeat_rows = rows_by_dimension(rows, dimension, d_invoice)\r\n    if not repeat_rows:\r\n        return\r\n\r\n    repeat_parts = path_parts(repeat_path)\r\n    if len(repeat_parts) &lt; 2 or repeat_parts[0] != \"Invoice\":\r\n        raise ValueError(f\"Invalid repeat path: {repeat_path}\")\r\n\r\n    container_path = \"\/\" + \"\/\".join(repeat_parts[:-1])\r\n    repeat_tag = repeat_parts[-1]\r\n    container = ensure_path(invoice, container_path)\r\n\r\n    marker_path = repeat_path + \"\/\"\r\n    # dXXX \u3054\u3068\u306e\u5404\u884c\u3092\u3001\u5bfe\u5fdc\u3059\u308b XML \u306e\u53cd\u5fa9\u8981\u7d20\u3068\u3057\u3066\u51fa\u529b\u3059\u308b\r\n    for repeat_row in repeat_rows:\r\n        repeat_elem = ET.SubElement(container, qname(repeat_tag))\r\n        for semantic_path, xpath in section_bindings:\r\n            _, suffix = xpath.split(marker_path, 1)\r\n            value = query_semantic_path(rows, semantic_path, d_invoice, current_row=repeat_row)\r\n            set_text_relative(repeat_elem, suffix, value)<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u51e6\u7406\u306f\uff0c\u6b21\u306e\u3088\u3046\u306b\u8003\u3048\u3089\u308c\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre>dTaxBreakdown \u306e\u5404\u884c\u3092\u53d6\u308a\u51fa\u3059\u3002\r\n\u5404\u884c\u306b\u3064\u3044\u3066 cac:TaxSubtotal \u3092\u4f5c\u6210\u3059\u308b\u3002\r\ntaxableAmount \u3092 cbc:TaxableAmount \u3078\u8a2d\u5b9a\u3059\u308b\u3002\r\ntaxAmount \u3092 cbc:TaxAmount \u3078\u8a2d\u5b9a\u3059\u308b\u3002\r\ntaxCategoryCode \u3068 taxRate \u3092 cac:TaxCategory \u3078\u8a2d\u5b9a\u3059\u308b\u3002<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u8acb\u6c42\u660e\u7d30\u3092xml\u3078\u5909\u63db\u3059\u308b\">4.9. \u8acb\u6c42\u660e\u7d30\u3092XML\u3078\u5909\u63db\u3059\u308b<\/h3>\n<div class=\"paragraph\">\n<p>\u8acb\u6c42\u660e\u7d30\u306f\uff0c<code>dInvoiceLine<\/code> \u306b\u5024\u304c\u3042\u308b\u884c\u3068\u3057\u3066\u8868\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def append_invoice_lines(invoice: ET.Element, rows: list[dict[str, str]], currency: str, d_invoice: str = \"1\") -&gt; None:\r\n    \"\"\"\u8acb\u6c42\u660e\u7d30\u884c\u3092 XML \u3078\u5c55\u958b\u3057\u307e\u3059\u3002\u73fe\u72b6\u306f\u7d50\u5408\u8868\u306e\u5b8c\u5168\u81ea\u52d5\u5316\u5bfe\u8c61\u5916\u3067\u3059\u3002\"\"\"\r\n    for line_row in rows_by_dimension(rows, \"dInvoiceLine\", d_invoice):\r\n        line = ET.SubElement(invoice, qname(\"cac:InvoiceLine\"))\r\n        ET.SubElement(line, qname(\"cbc:ID\")).text = line_row[\"lineID\"]\r\n        ET.SubElement(line, qname(\"cbc:InvoicedQuantity\"), {\"unitCode\": line_row.get(\"unitCode\") or \"EA\"}).text = line_row[\"invoicedQuantity\"]\r\n        ET.SubElement(line, qname(\"cbc:LineExtensionAmount\"), {\"currencyID\": currency}).text = line_row[\"lineExtensionAmount\"]\r\n\r\n        item = ET.SubElement(line, qname(\"cac:Item\"))\r\n        ET.SubElement(item, qname(\"cbc:Name\")).text = line_row[\"itemName\"]\r\n        if line_row.get(\"lineTaxCategoryCode\"):\r\n            tax_category = ET.SubElement(item, qname(\"cac:ClassifiedTaxCategory\"))\r\n            ET.SubElement(tax_category, qname(\"cbc:ID\")).text = line_row[\"lineTaxCategoryCode\"]\r\n            ET.SubElement(tax_category, qname(\"cbc:Percent\")).text = line_row[\"lineTaxRate\"]\r\n            scheme = ET.SubElement(tax_category, qname(\"cac:TaxScheme\"))\r\n            ET.SubElement(scheme, qname(\"cbc:ID\")).text = \"VAT\"\r\n\r\n        price = ET.SubElement(line, qname(\"cac:Price\"))\r\n        ET.SubElement(price, qname(\"cbc:PriceAmount\"), {\"currencyID\": currency}).text = line_row[\"unitPriceAmount\"]<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u69cb\u9020\u5316CSV\u5074\u3067\u306f\uff0c\u8acb\u6c42\u660e\u7d30\u306f1\u884c\u3067\u8868\u3055\u308c\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-csv\" data-lang=\"csv\">1,,,,,1,,,,,,,,,,,,,,,,,,INV-26-861-1,\u5546\u54c1A,S,10,10,EA,1000,10000<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u308c\u304c\uff0cXML\u3067\u306f <code>cac:InvoiceLine<\/code>\uff0c<code>cac:Item<\/code>\uff0c<code>cac:Price<\/code> \u306a\u3069\u306e\u968e\u5c64\u8981\u7d20\u3068\u3057\u3066\u5c55\u958b\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_xml\u304b\u3089csv\u3092\u751f\u6210\u3059\u308b\">5. XML\u304b\u3089CSV\u3092\u751f\u6210\u3059\u308b<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u9006\u65b9\u5411\u3067\u306f\uff0cXPath\u306b\u5bfe\u5fdc\u3059\u308bXML\u8981\u7d20\u3092\u63a2\u3057\uff0c\u305d\u306e\u5024\u3092CSV\u5217\u3078\u623b\u3059\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def append_header_row(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    row = new_empty_row(fieldnames, d_invoice)\r\n    row[\"invoiceNumber\"] = get_text(invoice, \"\/Invoice\/cbc:ID\")\r\n    row[\"issueDate\"] = get_text(invoice, \"\/Invoice\/cbc:IssueDate\")\r\n    row[\"invoiceTypeCode\"] = get_text(invoice, \"\/Invoice\/cbc:InvoiceTypeCode\")\r\n    row[\"currencyCode\"] = get_text(invoice, \"\/Invoice\/cbc:DocumentCurrencyCode\")\r\n    row[\"totalTaxAmount\"] = get_text(invoice, \"\/Invoice\/cac:TaxTotal\/cbc:TaxAmount\")\r\n    rows.append(row)\r\n\r\n\r\ndef append_party_rows(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    party_specs = [\r\n        (\"1\", \"Seller\", \"\/Invoice\/cac:AccountingSupplierParty\/cac:Party\"),\r\n        (\"2\", \"Buyer\", \"\/Invoice\/cac:AccountingCustomerParty\/cac:Party\"),\r\n    ]\r\n    for d_party, role, party_xpath in party_specs:\r\n        parts = [p for p in party_xpath.split(\"\/\") if p]\r\n        party = invoice\r\n        for part in parts[1:]:\r\n            party = party.find(qname(part))\r\n            if party is None:\r\n                break\r\n        if party is None:\r\n            continue\r\n        row = new_empty_row(fieldnames, d_invoice)\r\n        row[\"dInvoiceParty\"] = d_party\r\n        row[\"partyRole\"] = role\r\n        name = party.find(f\"{qname('cac:PartyName')}\/{qname('cbc:Name')}\")\r\n        tax_id = party.find(f\"{qname('cac:PartyTaxScheme')}\/{qname('cbc:CompanyID')}\")\r\n        row[\"partyName\"] = name.text if name is not None and name.text else \"\"\r\n        row[\"partyTaxID\"] = tax_id.text if tax_id is not None and tax_id.text else \"\"\r\n        rows.append(row)\r\n\r\n\r\ndef append_document_reference_rows(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    ref_specs = [\r\n        (\"Order\", \"\/Invoice\/cac:OrderReference\/cbc:ID\"),\r\n        (\"Delivery\", \"\/Invoice\/cac:DespatchDocumentReference\/cbc:ID\"),\r\n    ]\r\n    ref_no = 1\r\n    for ref_type, ref_xpath in ref_specs:\r\n        ref_id = get_text(invoice, ref_xpath)\r\n        if ref_id:\r\n            row = new_empty_row(fieldnames, d_invoice)\r\n            row[\"dDocumentReference\"] = str(ref_no)\r\n            row[\"referenceType\"] = ref_type\r\n            row[\"referenceID\"] = ref_id\r\n            rows.append(row)\r\n            ref_no += 1\r\n\r\n\r\ndef append_payment_row(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    due_date = get_text(invoice, \"\/Invoice\/cbc:DueDate\")\r\n    payment_id = get_text(invoice, \"\/Invoice\/cac:PaymentMeans\/cbc:PaymentID\")\r\n    if due_date or payment_id:\r\n        row = new_empty_row(fieldnames, d_invoice)\r\n        row[\"dPayment\"] = \"1\"\r\n        row[\"paymentDueDate\"] = due_date\r\n        row[\"paymentReference\"] = payment_id\r\n        rows.append(row)\r\n\r\n\r\ndef append_repeating_rows_from_bindings(\r\n    rows: list[dict[str, str]],\r\n    invoice: ET.Element,\r\n    fieldnames: list[str],\r\n    bindings: list[Binding],\r\n    d_invoice: str = \"1\",\r\n) -&gt; None:\r\n    # binding \u5b9a\u7fa9\u3092\u898b\u3066\u3001dXXX \u306b\u5bfe\u5fdc\u3059\u308b XML \u306e\u53cd\u5fa9\u968e\u5c64\u3092\u7279\u5b9a\u3059\u308b\r\n    repeat_defs = infer_repeat_definitions(bindings)\r\n    for dimension, repeat_path in repeat_defs.items():\r\n        # \u540c\u3058\u7e70\u8fd4\u3057\u968e\u5c64\u306b\u5c5e\u3059\u308b binding \u7fa4\u3092\u96c6\u3081\u308b\r\n        section_bindings = bindings_for_repeat_path(bindings, repeat_path)\r\n        repeat_parts = path_parts(repeat_path)\r\n        if len(repeat_parts) &lt; 2 or repeat_parts[0] != \"Invoice\":\r\n            continue\r\n\r\n        parent_path = \"\/\" + \"\/\".join(repeat_parts[:-1])\r\n        repeat_tag = repeat_parts[-1]\r\n        parent_elem = invoice\r\n        for part in path_parts(parent_path)[1:]:\r\n            parent_elem = parent_elem.find(qname(part))\r\n            if parent_elem is None:\r\n                break\r\n        if parent_elem is None:\r\n            continue\r\n\r\n        # XML \u5074\u306e\u53cd\u5fa9\u8981\u7d20\u3092\u9806\u306b\u8aad\u307f\u3001\u69cb\u9020\u5316CSV\u306e dXXX \u884c\u3078\u623b\u3059\r\n        repeat_elems = parent_elem.findall(qname(repeat_tag))\r\n        marker_path = repeat_path + \"\/\"\r\n        for i, repeat_elem in enumerate(repeat_elems, start=1):\r\n            row = new_empty_row(fieldnames, d_invoice)\r\n            row[dimension] = str(i)\r\n            for semantic_path, xpath in section_bindings:\r\n                dim_target = direct_dimension_target(semantic_path)\r\n                if not dim_target or dim_target[0] != dimension:\r\n                    continue\r\n                target_field = dim_target[1]\r\n                _, suffix = xpath.split(marker_path, 1)\r\n                row[target_field] = get_text_relative(repeat_elem, suffix)\r\n            rows.append(row)\r\n\r\n\r\ndef append_invoice_line_rows(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    for i, line in enumerate(invoice.findall(qname(\"cac:InvoiceLine\")), start=1):\r\n        row = new_empty_row(fieldnames, d_invoice)\r\n        row[\"dInvoiceLine\"] = str(i)\r\n        line_id = line.find(qname(\"cbc:ID\"))\r\n        quantity = line.find(qname(\"cbc:InvoicedQuantity\"))\r\n        line_amount = line.find(qname(\"cbc:LineExtensionAmount\"))\r\n        item = line.find(qname(\"cac:Item\"))\r\n        price = line.find(qname(\"cac:Price\"))\r\n        row[\"lineID\"] = line_id.text if line_id is not None and line_id.text else \"\"\r\n        if quantity is not None:\r\n            row[\"invoicedQuantity\"] = quantity.text or \"\"\r\n            row[\"unitCode\"] = quantity.attrib.get(\"unitCode\", \"\")\r\n        row[\"lineExtensionAmount\"] = line_amount.text if line_amount is not None and line_amount.text else \"\"\r\n        if item is not None:\r\n            name = item.find(qname(\"cbc:Name\"))\r\n            row[\"itemName\"] = name.text if name is not None and name.text else \"\"\r\n            tax_category = item.find(qname(\"cac:ClassifiedTaxCategory\"))\r\n            if tax_category is not None:\r\n                cat_id = tax_category.find(qname(\"cbc:ID\"))\r\n                percent = tax_category.find(qname(\"cbc:Percent\"))\r\n                row[\"lineTaxCategoryCode\"] = cat_id.text if cat_id is not None and cat_id.text else \"\"\r\n                row[\"lineTaxRate\"] = percent.text if percent is not None and percent.text else \"\"\r\n        if price is not None:\r\n            price_amount = price.find(qname(\"cbc:PriceAmount\"))\r\n            row[\"unitPriceAmount\"] = price_amount.text if price_amount is not None and price_amount.text else \"\"\r\n        rows.append(row)\r\n\r\n\r\ndef ubl_xml_to_csv_rows(invoice: ET.Element, fieldnames: list[str], bindings: list[Binding], d_invoice: str = \"1\") -&gt; list[dict[str, str]]:\r\n    \"\"\"XML \u3092\u8aad\u307f\u3001\u69cb\u9020\u5316CSV\u306e\u884c\u30ea\u30b9\u30c8\u3078\u623b\u3057\u307e\u3059\u3002\"\"\"\r\n    rows: list[dict[str, str]] = []\r\n    append_header_row(rows, invoice, fieldnames, d_invoice)\r\n    append_party_rows(rows, invoice, fieldnames, d_invoice)\r\n    append_document_reference_rows(rows, invoice, fieldnames, d_invoice)\r\n    append_payment_row(rows, invoice, fieldnames, d_invoice)\r\n    append_repeating_rows_from_bindings(rows, invoice, fieldnames, bindings, d_invoice)\r\n    append_invoice_line_rows(rows, invoice, fieldnames, d_invoice)\r\n    return rows<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u51e6\u7406\u306b\u3088\u308a\uff0cXML\u4e0a\u306e\u30d8\u30c3\u30c0\u30fc\uff0c\u5f53\u4e8b\u8005\uff0c\u53c2\u7167\u6587\u66f8\uff0c\u652f\u6255\u60c5\u5831\uff0c\u7a0e\u7387\u5225\u5185\u8a33\uff0c\u8acb\u6c42\u660e\u7d30\u304c\uff0c\u69cb\u9020\u5316CSV\u306e\u884c\u3068\u3057\u3066\u518d\u69cb\u6210\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u51fa\u529b\u51e6\u7406\u3068main\u95a2\u6570\">6. \u51fa\u529b\u51e6\u7406\u3068main\u95a2\u6570<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u6700\u5f8c\u306b\uff0cXML\u3068CSV\u3092\u66f8\u304d\u51fa\u3059\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def rows_to_csv(rows: list[dict[str, str]], fieldnames: list[str]) -&gt; str:\r\n    out = io.StringIO()\r\n    writer = csv.DictWriter(out, fieldnames=fieldnames, lineterminator=\"\\n\")\r\n    writer.writeheader()\r\n    writer.writerows(rows)\r\n    return out.getvalue()\r\n\r\n\r\ndef write_xml(elem: ET.Element, path: str | Path) -&gt; None:\r\n    tree = ET.ElementTree(elem)\r\n    ET.indent(tree, space=\"  \")\r\n    tree.write(path, encoding=\"utf-8\", xml_declaration=True)<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u30b3\u30de\u30f3\u30c9\u30e9\u30a4\u30f3\u5f15\u6570\u306e\u51e6\u7406\u306f\u6b21\u306e\u3068\u304a\u308a\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-python\" data-lang=\"python\">def main() -&gt; None:\r\n    parser = argparse.ArgumentParser(\r\n        description=\"\u69cb\u9020\u5316CSV\u3068\u7c21\u7565\u5316\u3057\u305f UBL Invoice XML \u306e\u76f8\u4e92\u5909\u63db\u30b5\u30f3\u30d7\u30eb\",\r\n        epilog=\"\u4f8b: py .\\\\syntax_binding.py .\\\\invoice.csv .\\\\bindings.csv --xml-out .\\\\invoice.xml --roundtrip-out .\\\\roundtrip.csv\",\r\n    )\r\n    parser.add_argument(\"invoice_csv\", type=Path, help=\"\u5165\u529b\u3068\u306a\u308b\u69cb\u9020\u5316CSV\u30d5\u30a1\u30a4\u30eb\")\r\n    parser.add_argument(\"bindings_csv\", type=Path, help=\"Semantic path \u3068 XPath \u3092\u5bfe\u5fdc\u4ed8\u3051\u305f binding CSV\")\r\n    parser.add_argument(\"--xml-out\", type=Path, default=Path(\"invoice.xml\"), help=\"\u751f\u6210\u3059\u308b XML \u306e\u51fa\u529b\u5148\")\r\n    parser.add_argument(\"--roundtrip-out\", type=Path, default=Path(\"roundtrip.csv\"), help=\"XML \u3092\u8aad\u307f\u623b\u3057\u3066\u518d\u69cb\u6210\u3057\u305f CSV \u306e\u51fa\u529b\u5148\")\r\n    args = parser.parse_args()\r\n\r\n    # 1) \u5165\u529b CSV \u3068 binding CSV \u3092\u8aad\u3080\r\n    rows = read_core_csv_file(args.invoice_csv)\r\n    bindings = read_bindings_csv_file(args.bindings_csv)\r\n    # 2) CSV -&gt; XML \u5909\u63db\r\n    invoice = csv_to_ubl_xml(rows, bindings)\r\n    write_xml(invoice, args.xml_out)\r\n\r\n    # 3) XML -&gt; CSV \u306e\u9006\u5909\u63db\u3092\u884c\u3044\u3001roundtrip.csv \u3092\u51fa\u529b\u3059\u308b\r\n    fieldnames = list(rows[0].keys()) if rows else []\r\n    roundtrip_rows = ubl_xml_to_csv_rows(invoice, fieldnames, bindings)\r\n    args.roundtrip_out.write_text(rows_to_csv(roundtrip_rows, fieldnames), encoding=\"utf-8\")<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u5b9f\u884c\u7d50\u679c\">7. \u5b9f\u884c\u7d50\u679c<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u5b9f\u884c\u3059\u308b\u3068\uff0c<code>invoice.xml<\/code> \u3068 <code>roundtrip.csv<\/code> \u304c\u4f5c\u6210\u3055\u308c\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-bash\" data-lang=\"bash\">python3 syntax_binding.py \\\r\n  --input-csv invoice.csv \\\r\n  --bindings-csv bindings.csv \\\r\n  --xml-out invoice.xml \\\r\n  --roundtrip-csv roundtrip.csv \\\r\n  --print-xml<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u751f\u6210\u3055\u308c\u308bXML\u306e\u4e00\u90e8\u306f\u6b21\u306e\u3088\u3046\u306b\u306a\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-xml\" data-lang=\"xml\">&lt;?xml version='1.0' encoding='utf-8'?&gt;\r\n&lt;Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\" xmlns:cac=\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\" xmlns:cbc=\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\"&gt;\r\n  &lt;cbc:ID&gt;INV-26-861&lt;\/cbc:ID&gt;\r\n  &lt;cbc:IssueDate&gt;2026-06-20&lt;\/cbc:IssueDate&gt;\r\n  &lt;cbc:InvoiceTypeCode&gt;380&lt;\/cbc:InvoiceTypeCode&gt;\r\n  &lt;cbc:DocumentCurrencyCode&gt;JPY&lt;\/cbc:DocumentCurrencyCode&gt;\r\n  &lt;cac:AccountingSupplierParty&gt;\r\n    &lt;cac:Party&gt;\r\n      &lt;cac:PartyName&gt;\r\n        &lt;cbc:Name&gt;\u58f2\u624b\u682a\u5f0f\u4f1a\u793e&lt;\/cbc:Name&gt;\r\n      &lt;\/cac:PartyName&gt;\r\n      &lt;cac:PartyTaxScheme&gt;\r\n        &lt;cbc:CompanyID&gt;T1234567890123&lt;\/cbc:CompanyID&gt;\r\n      &lt;\/cac:PartyTaxScheme&gt;\r\n    &lt;\/cac:Party&gt;\r\n  &lt;\/cac:AccountingSupplierParty&gt;\r\n  &lt;cac:AccountingCustomerParty&gt;\r\n    &lt;cac:Party&gt;\r\n      &lt;cac:PartyName&gt;\r\n        &lt;cbc:Name&gt;\u8cb7\u624b\u682a\u5f0f\u4f1a\u793e&lt;\/cbc:Name&gt;\r\n      &lt;\/cac:PartyName&gt;\r\n    &lt;\/cac:Party&gt;\r\n  &lt;\/cac:AccountingCustomerParty&gt;\r\n  &lt;cac:OrderReference&gt;\r\n    &lt;cbc:ID&gt;PO-2026-0001&lt;\/cbc:ID&gt;\r\n  &lt;\/cac:OrderReference&gt;\r\n  &lt;cac:DespatchDocumentReference&gt;\r\n    &lt;cbc:ID&gt;DN-2026-0001&lt;\/cbc:ID&gt;\r\n  &lt;\/cac:DespatchDocumentReference&gt;\r\n  &lt;cbc:DueDate&gt;2026-07-31&lt;\/cbc:DueDate&gt;\r\n  &lt;cac:PaymentMeans&gt;\r\n    &lt;cbc:PaymentID&gt;INV-2026-0001&lt;\/cbc:PaymentID&gt;\r\n  &lt;\/cac:PaymentMeans&gt;\r\n  &lt;cac:TaxTotal&gt;\r\n    &lt;cbc:TaxAmount currencyID=\"JPY\"&gt;1472&lt;\/cbc:TaxAmount&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>XML\u3092\u8aad\u307f\u623b\u3057\u3066\u751f\u6210\u3057\u305fCSV\u306f\u6b21\u306e\u3088\u3046\u306b\u306a\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-csv\" data-lang=\"csv\">dInvoice,dInvoiceParty,dDocumentReference,dPayment,dTaxBreakdown,dInvoiceLine,invoiceNumber,issueDate,invoiceTypeCode,currencyCode,totalAmount,totalTaxAmount,partyRole,partyName,partyTaxID,referenceType,referenceID,paymentDueDate,paymentMeansCode,paymentReference,taxCategoryCode,taxRate,taxableAmount,taxAmount,lineID,itemName,lineTaxCategoryCode,lineTaxRate,invoicedQuantity,unitCode,unitPriceAmount,lineExtensionAmount\r\n1,,,,,,INV-26-861,2026-06-20,380,JPY,,1472,,,,,,,,,,,,,,,,,,,,\r\n1,1,,,,,,,,,,,Seller,\u58f2\u624b\u682a\u5f0f\u4f1a\u793e,T1234567890123,,,,,,,,,,,,,,,,,\r\n1,2,,,,,,,,,,,Buyer,\u8cb7\u624b\u682a\u5f0f\u4f1a\u793e,,,,,,,,,,,,,,,,,,\r\n1,,1,,,,,,,,,,,,,Order,PO-2026-0001,,,,,,,,,,,,,,,\r\n1,,2,,,,,,,,,,,,,Delivery,DN-2026-0001,,,,,,,,,,,,,,,\r\n1,,,1,,,,,,,,,,,,,,2026-07-31,,INV-2026-0001,,,,,,,,,,,,\r\n1,,,,1,,,,,,,,,,,,,,,,S,10,12320,1232,,,,,,,,\r\n1,,,,2,,,,,,,,,,,,,,,,AA,8,3010,240,,,,,,,,\r\n1,,,,,1,,,,,,,,,,,,,,,,,,,INV-26-861-1,\u5546\u54c1A,S,10,10,EA,1000,10000\r\n1,,,,,2,,,,,,,,,,,,,,,,,,,INV-26-861-2,\u5546\u54c1B,S,10,4,EA,580,2320\r\n1,,,,,3,,,,,,,,,,,,,,,,,,,INV-26-861-3,\u98df\u54c1C,AA,8,7,EA,430,3010<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u30d7\u30ed\u30b0\u30e9\u30de\u5411\u3051\u88dc\u8db3\">8. \u30d7\u30ed\u30b0\u30e9\u30de\u5411\u3051\u88dc\u8db3<\/h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"_\u306a\u305c\u69cb\u6587\u7d50\u5408\u8868\u3092csv\u306b\u51fa\u3059\u306e\u304b\">8.1. \u306a\u305c\u69cb\u6587\u7d50\u5408\u8868\u3092CSV\u306b\u51fa\u3059\u306e\u304b<\/h3>\n<div class=\"paragraph\">\n<p>\u69cb\u6587\u7d50\u5408\u8868\u3092Python\u30b3\u30fc\u30c9\u306b\u57cb\u3081\u8fbc\u3080\u3068\uff0c\u5bfe\u5fdc\u5148\u306eXML\u69cb\u6587\u304c\u5909\u308f\u308b\u305f\u3073\u306b\u30d7\u30ed\u30b0\u30e9\u30e0\u3092\u4fee\u6b63\u3059\u308b\u5fc5\u8981\u304c\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4e00\u65b9\uff0c<code>bindings.csv<\/code> \u3068\u3057\u3066\u5916\u90e8\u5316\u3059\u308c\u3070\uff0c\u30d7\u30ed\u30b0\u30e9\u30e0\u672c\u4f53\u306f\u6b21\u306e\u6c4e\u7528\u51e6\u7406\u306b\u96c6\u4e2d\u3067\u304d\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre>CSV\u3092\u8aad\u307f\u8fbc\u3080\u3002\r\nSemanticPath\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b\u3002\r\nXPath\u3067XML\u8981\u7d20\u3092\u4f5c\u308b\u3002\r\n\u5024\u3092\u8a2d\u5b9a\u3059\u308b\u3002<\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u65b9\u5f0f\u3067\u306f\uff0c\u5225\u306eXML\u69cb\u6587\u53c8\u306fJSON\u69cb\u6587\u3078\u5bfe\u5fdc\u3059\u308b\u5834\u5408\u306b\u3082\uff0c\u307e\u305a\u5909\u66f4\u5bfe\u8c61\u3068\u306a\u308b\u306e\u306f\u7d50\u5408\u8868\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u9650\u5b9a\u3055\u308c\u305fsemanticpath_subset\">8.2. \u9650\u5b9a\u3055\u308c\u305fSemanticPath subset<\/h3>\n<div class=\"paragraph\">\n<p>\u3053\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u306f\uff0cSemanticPath\u3092\u610f\u56f3\u7684\u306b\u9650\u5b9a\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\"><code class=\"language-text\" data-lang=\"text\">$.Invoice.field\r\n$.Invoice.dimension[?@.filterField=filterValue].field<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3053\u308c\u306f\uff0c\u69cb\u6587\u7d50\u5408\u8868\u3067\u5b9f\u969b\u306b\u5fc5\u8981\u306a\u6307\u5b9a\u3060\u3051\u3092\u5b89\u5168\u306b\u6271\u3046\u305f\u3081\u3067\u3042\u308b\u3002\u6c4e\u7528\u5f0f\u3092\u3059\u3079\u3066\u8a31\u53ef\u3059\u308b\u3068\uff0c\u5b9f\u88c5\u304c\u8907\u96d1\u306b\u306a\u308a\uff0c\u691c\u8a3c\u3082\u96e3\u3057\u304f\u306a\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<div class=\"sect2\">\n<h3 id=\"_\u7e70\u8fd4\u3057\u69cb\u9020\u306f\u5225\u898f\u5247\u306b\u3057\u3066\u3044\u308b\">8.3. \u7e70\u8fd4\u3057\u69cb\u9020\u306f\u5225\u898f\u5247\u306b\u3057\u3066\u3044\u308b<\/h3>\n<div class=\"paragraph\">\n<p><code>dTaxBreakdown<\/code> \u3084 <code>dInvoiceLine<\/code> \u306f\uff0c\u5358\u4e00\u306e\u5024\u3092\u5358\u4e00\u306eXPath\u3078\u5199\u3059\u3060\u3051\u3067\u306f\u8868\u73fe\u3067\u304d\u306a\u3044\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u305d\u306e\u305f\u3081\uff0c\u672c\u30b5\u30f3\u30d7\u30eb\u3067\u306f\uff0c\u5358\u7d14\u9805\u76ee\u306f <code>bindings.csv<\/code> \u3067\u51e6\u7406\u3057\uff0c\u7e70\u8fd4\u3057\u69cb\u9020\u306f <code>append_tax_total()<\/code> \u3068 <code>append_invoice_lines()<\/code> \u3067\u51e6\u7406\u3057\u3066\u3044\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u5b9f\u904b\u7528\u3067\u306f\uff0c\u7e70\u8fd4\u3057\u69cb\u9020\u306e\u751f\u6210\u898f\u5247\u3082\u7d50\u5408\u5b9a\u7fa9\u5074\u3078\u5916\u90e8\u5316\u3057\u3066\u3044\u304f\u3053\u3068\u304c\u6b21\u306e\u8ab2\u984c\u306b\u306a\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u304a\u308f\u308a\u306b\">9. \u304a\u308f\u308a\u306b<\/h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>\u69cb\u6587\u7d50\u5408\u8868\u3092\u7528\u3044\u308b\u3068\uff0c\u5909\u63db\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u8003\u3048\u65b9\u304c\u5909\u308f\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u5f93\u6765\u306f\uff0c\u5909\u63db\u5143\u9805\u76ee\u3068\u5909\u63db\u5148\u9805\u76ee\u3092\u30d7\u30ed\u30b0\u30e9\u30e0\u4e2d\u306b\u76f4\u63a5\u66f8\u304d\u8fbc\u3080\u3053\u3068\u304c\u591a\u304b\u3063\u305f\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u3057\u304b\u3057\uff0cSemanticPath \u3068 XPath \u306e\u5bfe\u5fdc\u3092\u69cb\u6587\u7d50\u5408\u8868\u3068\u3057\u3066\u5b9a\u7fa9\u3059\u308c\u3070\uff0c\u30d7\u30ed\u30b0\u30e9\u30e0\u672c\u4f53\u306f\uff0c\u6b21\u306e\u6c4e\u7528\u51e6\u7406\u306b\u96c6\u4e2d\u3067\u304d\u308b\u3002<\/p>\n<\/div>\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre>SemanticPath\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b\u3002\r\nXPath\u3067XML\u8981\u7d20\u3092\u4f5c\u308b\u3002\r\n\u5024\u3092\u8a2d\u5b9a\u3059\u308b\u3002\r\n\u9006\u65b9\u5411\u3067\u306f\uff0cXPath\u3067\u5024\u3092\u53d6\u5f97\u3057\uff0c\u69cb\u9020\u5316CSV\u884c\u3078\u623b\u3059\u3002<\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>\u4eca\u56de\u306e\u6539\u8a02\u3067\u306f\uff0c\u305d\u306e\u7b2c\u4e00\u6b69\u3068\u3057\u3066\uff0c\u8acb\u6c42\u66f8CSV\u3068\u69cb\u6587\u7d50\u5408\u8868\u3092\u5916\u90e8CSV\u3068\u3057\u3066\u8aad\u307f\u8fbc\u3080\u5f62\u306b\u3057\u305f\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u65e5\u672c\u7248\u30b3\u30a2\u30a4\u30f3\u30dc\u30a4\u30b9\uff08\u69cb\u9020\u5316CSV\uff09\u306f\uff0cJP PINT\u3092\u7f6e\u304d\u63db\u3048\u308b\u3082\u306e\u3067\u306f\u306a\u3044\u3002JP PINT UBL\uff0c\u65e2\u5b58EDI\uff0cERP\uff0c\u4f1a\u8a08\u30b7\u30b9\u30c6\u30e0\u306e\u9593\u306b\u5165\u308a\uff0c\u305d\u308c\u305e\u308c\u306e\u69cb\u6587\u3092\u5171\u901a\u306e\u610f\u5473\u306b\u7d50\u3073\u4ed8\u3051\u308b\u305f\u3081\u306e\u4e2d\u9593\u7684\u306a\u30bb\u30de\u30f3\u30c6\u30a3\u30c3\u30af\u30e2\u30c7\u30eb\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>\u305d\u306e\u5b9f\u88c5\u30a4\u30e1\u30fc\u30b8\u3092\u3064\u304b\u3080\u3046\u3048\u3067\uff0c\u4eca\u56de\u306e\u3088\u3046\u306a\u5c0f\u3055\u306aPython\u30d7\u30ed\u30b0\u30e9\u30e0\u306f\u6709\u52b9\u3067\u3042\u308b\u3002<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"sect1\">\n<h2 id=\"_\u53c2\u8003\u30b5\u30f3\u30d7\u30eb\u30bd\u30fc\u30b9\">10. \u53c2\u8003\uff1a\u30b5\u30f3\u30d7\u30eb\u30bd\u30fc\u30b9<\/h2>\n<div class=\"sectionbody\">\n<div class=\"listingblock\">\n<div class=\"content\">\n<pre class=\"highlight\" style=\"max-width: 100%; max-height: 400px; overflow-x: auto; overflow-y: auto; whitespace: pre; display: block;\"><code class=\"language-python\" data-lang=\"python\">\"\"\"\r\nsyntax_binding.py\r\n\r\n\u69cb\u9020\u5316CSV\uff08Japan Core Invoice \u306e\u8aac\u660e\u7528\u30b5\u30f3\u30d7\u30eb\uff09\u3068\r\n\u7c21\u7565\u5316\u3057\u305f UBL 2.1 Invoice XML \u306e\u76f8\u4e92\u5909\u63db\u3092\u884c\u3046 Python \u30b9\u30af\u30ea\u30d7\u30c8\u3067\u3059\u3002\r\n\r\n\u8a2d\u8a08\u30fb\u57f7\u7b46:\r\n  \u4e09\u5206\u4e00\u4fe1\u4e4b\uff08\u4e09\u5206\u4e00\u6280\u8853\u58eb\u4e8b\u52d9\u6240\uff09\r\n\r\n\u4f5c\u6210\u65e5: 2026-07-02\r\n\u6539\u8a02\u65e5: 2026-07-02\r\n\r\n\u3053\u306e\u30b9\u30af\u30ea\u30d7\u30c8\u3067\u793a\u3057\u305f\u3044\u3053\u3068\r\n1. \u5909\u63db\u4ed5\u69d8\u3092\u30d7\u30ed\u30b0\u30e9\u30e0\u672c\u4f53\u306b\u57cb\u3081\u8fbc\u3080\u306e\u3067\u306f\u306a\u304f\u3001bindings.csv \u306b\u5916\u51fa\u3057\u3067\u304d\u308b\u3053\u3068\r\n2. \u69cb\u9020\u5316CSV\u5074\u306e\u610f\u5473\u4f4d\u7f6e\u3092 Semantic path \u3067\u6307\u5b9a\u3067\u304d\u308b\u3053\u3068\r\n3. XML \u5074\u306e\u69cb\u6587\u4f4d\u7f6e\u3092 XPath \u3067\u6307\u5b9a\u3067\u304d\u308b\u3053\u3068\r\n4. dXXX \u5217\u306b\u5024\u304c\u3042\u308b\u884c\u3092\u3001\u7e70\u8fd4\u3057\u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3\uff08\u968e\u5c64\uff09\u3068\u3057\u3066\u6271\u3048\u308b\u3053\u3068\r\n5. XML \u2192 CSV \u306e\u9006\u5909\u63db\u3067\u3082\u3001\u540c\u3058\u7d50\u5408\u5b9a\u7fa9\u306e\u8003\u3048\u65b9\u3092\u4f7f\u3048\u308b\u3053\u3068\r\n\r\n\u3053\u306e\u30b5\u30f3\u30d7\u30eb\u306e\u524d\u63d0\r\n- invoice.csv \u306f\u3001JP PINT \u306e\u5b8c\u5168\u5b9f\u88c5\u30c7\u30fc\u30bf\u3067\u306f\u306a\u304f\u3001\u8aac\u660e\u7528\u306e\u6982\u5ff5\u30b5\u30f3\u30d7\u30eb\u3067\u3059\u3002\r\n- bindings.csv \u3082\u3001\u4ee3\u8868\u7684\u306a\u5b9a\u7fa9\u9805\u76ee\u306e\u629c\u7c8b\u3067\u3042\u308a\u3001JP PINT \u5fc5\u9808\u9805\u76ee\u3092\u3059\u3079\u3066\u542b\u3080\u5b8c\u5168\u7248\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\r\n- \u7a0e\u7387\u5225\u5185\u8a33\uff08dTaxBreakdown\uff09\u306f\u3001\u69cb\u6587\u7d50\u5408\u8868\u3060\u3051\u3067\u51e6\u7406\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u307e\u3059\u3002\r\n- \u660e\u7d30\u884c\uff08cac:InvoiceLine\uff09\u306f\u3001\u306a\u304a Python \u5074\u306e\u88dc\u52a9\u51e6\u7406\u3092\u6b8b\u3057\u3066\u3044\u307e\u3059\u3002\r\n\r\n\u4e3b\u306a\u30d5\u30a1\u30a4\u30eb\r\n- invoice.csv       : \u69cb\u9020\u5316CSV\u306e\u5165\u529b\u30c7\u30fc\u30bf\r\n- bindings.csv      : Semantic path \u3068 XPath \u306e\u5bfe\u5fdc\u8868\r\n- invoice.xml       : \u751f\u6210\u3055\u308c\u308b XML\r\n- roundtrip.csv     : XML \u3092\u8aad\u307f\u623b\u3057\u3066\u518d\u69cb\u6210\u3057\u305f CSV\r\n\r\n\u5b9f\u884c\u65b9\u6cd5\uff08Windows PowerShell\uff09\r\n1) \u30ab\u30ec\u30f3\u30c8\u30d5\u30a9\u30eb\u30c0\u3092\u3001\u3053\u306e\u30b9\u30af\u30ea\u30d7\u30c8\u3068 invoice.csv \/ bindings.csv \u304c\u3042\u308b\u5834\u6240\u3078\u79fb\u52d5\u3057\u307e\u3059\u3002\r\n2) \u305d\u306e\u3046\u3048\u3067\u3001\u6b21\u3092\u5b9f\u884c\u3057\u307e\u3059\u3002\r\n\r\n    py .\\syntax_binding.py .\\invoice.csv .\\bindings.csv\r\n\r\n\u51fa\u529b\u5148\u3092\u6307\u5b9a\u3059\u308b\u5834\u5408\u306f\u3001\u6b21\u306e\u3088\u3046\u306b\u3057\u307e\u3059\u3002\r\n\r\n    py .\\syntax_binding.py .\\invoice.csv .\\bindings.csv `\r\n      --xml-out .\\invoice.xml `\r\n      --roundtrip-out .\\roundtrip.csv\r\n\r\nPython Launcher \u304c\u4f7f\u3048\u306a\u3044\u5834\u5408\u306f\u3001python \u30b3\u30de\u30f3\u30c9\u3067\u3082\u69cb\u3044\u307e\u305b\u3093\u3002\r\n\r\n    python .\\syntax_binding.py .\\invoice.csv .\\bindings.csv\r\n\r\n\u5b9f\u884c\u7d50\u679c\r\n- \u6307\u5b9a\u3057\u305f XML \u51fa\u529b\u5148\u306b invoice.xml \u304c\u751f\u6210\u3055\u308c\u307e\u3059\u3002\r\n- \u6307\u5b9a\u3057\u305f CSV \u51fa\u529b\u5148\u306b roundtrip.csv \u304c\u751f\u6210\u3055\u308c\u307e\u3059\u3002\r\n\r\n\u6ce8\u610f\r\n\u3053\u306e\u30b9\u30af\u30ea\u30d7\u30c8\u306f\u3001\u69cb\u6587\u7d50\u5408\u8868\u306e\u8003\u3048\u65b9\u3092\u8aac\u660e\u3059\u308b\u305f\u3081\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u3059\u3002\r\n\u672c\u756a\u904b\u7528\u3067\u306f\u3001JP PINT \u306e\u5b8c\u5168\u306a\u5fc5\u9808\u9805\u76ee\u3001\u30b3\u30fc\u30c9\u30ea\u30b9\u30c8\u3001\u696d\u52d9\u898f\u5247\u3001\u59a5\u5f53\u6027\u691c\u8a3c\u3092\r\n\u8ffd\u52a0\u3057\u3066\u3044\u304f\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\r\n\"\"\"\r\n\r\n# tag::imports[]\r\nfrom __future__ import annotations\r\n\r\nimport argparse\r\nimport csv\r\nimport io\r\nimport re\r\nimport xml.etree.ElementTree as ET\r\nfrom pathlib import Path\r\n# end::imports[]\r\n\r\n# \u69cb\u6587\u7d50\u5408\u8868\u306e1\u884c: (Semantic path, XPath)\r\nBinding = tuple[str, str]\r\n\r\n# tag::namespace[]\r\nUBL_NS = \"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"\r\nCBC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\"\r\nCAC_NS = \"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\"\r\n\r\nNS = {\r\n    \"\": UBL_NS,\r\n    \"cbc\": CBC_NS,\r\n    \"cac\": CAC_NS,\r\n}\r\n\r\n# XML \u51fa\u529b\u6642\u306b\u898b\u3084\u3059\u3044\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u4ed8\u304d\u3067\u540d\u524d\u7a7a\u9593\u3092\u767b\u9332\u3059\u308b\r\nfor prefix, uri in NS.items():\r\n    ET.register_namespace(prefix, uri)\r\n\r\n\r\ndef qname(name: str) -&gt; str:\r\n    \"\"\"cbc:ID \u306e\u3088\u3046\u306a\u540d\u524d\u3092 ElementTree \u7528\u306e QName \u3078\u5909\u63db\u3057\u307e\u3059\u3002\"\"\"\r\n    if \":\" in name:\r\n        prefix, local = name.split(\":\", 1)\r\n        return f\"{{{NS[prefix]}}}{local}\"\r\n    return f\"{{{UBL_NS}}}{name}\"\r\n# end::namespace[]\r\n\r\n# tag::read_csv[]\r\ndef read_core_csv(text: str) -&gt; list[dict[str, str]]:\r\n    \"\"\"\u69cb\u9020\u5316CSV\u6587\u5b57\u5217\u3092\u30011\u884c1\u8f9e\u66f8\u306e\u30ea\u30b9\u30c8\u3078\u5909\u63db\u3057\u307e\u3059\u3002\"\"\"\r\n    return list(csv.DictReader(io.StringIO(text)))\r\n\r\n\r\ndef read_core_csv_file(path: str | Path, encoding: str = \"utf-8-sig\") -&gt; list[dict[str, str]]:\r\n    \"\"\"\u69cb\u9020\u5316CSV\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u307e\u3059\u3002Excel \u4fdd\u5b58\u6642\u306e BOM \u306b\u3082\u5bfe\u5fdc\u3059\u308b\u305f\u3081 utf-8-sig \u3092\u4f7f\u3044\u307e\u3059\u3002\"\"\"\r\n    return read_core_csv(Path(path).read_text(encoding=encoding))\r\n# end::read_csv[]\r\n\r\n# tag::binding_read[]\r\ndef read_bindings_csv(text: str) -&gt; list[Binding]:\r\n    \"\"\"bindings.csv \u3092\u8aad\u307f\u8fbc\u307f\u3001(semantic_path, xpath) \u306e\u30ea\u30b9\u30c8\u3078\u5909\u63db\u3057\u307e\u3059\u3002\"\"\"\r\n    bindings: list[Binding] = []\r\n    reader = csv.DictReader(io.StringIO(text))\r\n    if reader.fieldnames is None:\r\n        raise ValueError(\"Binding CSV has no header\")\r\n\r\n    fieldnames = [name.lstrip(\"\\ufeff\") for name in reader.fieldnames]\r\n    if \"semantic_path\" not in fieldnames or \"xpath\" not in fieldnames:\r\n        raise ValueError(\"Binding CSV must have semantic_path and xpath columns\")\r\n\r\n    for line_no, row in enumerate(reader, start=2):\r\n        normalized = {k.lstrip(\"\\ufeff\"): (v or \"\").strip() for k, v in row.items()}\r\n        semantic_path = normalized.get(\"semantic_path\", \"\")\r\n        xpath = normalized.get(\"xpath\", \"\")\r\n        if not semantic_path and not xpath:\r\n            continue\r\n        if not semantic_path or not xpath:\r\n            raise ValueError(f\"Incomplete binding at line {line_no}: {row!r}\")\r\n        if not xpath.startswith(\"\/Invoice\/\") and xpath != \"\/Invoice\":\r\n            raise ValueError(f\"XPath must start with \/Invoice at line {line_no}: {xpath!r}\")\r\n        bindings.append((semantic_path, xpath))\r\n    return bindings\r\n\r\n\r\ndef read_bindings_csv_file(path: str | Path, encoding: str = \"utf-8-sig\") -&gt; list[Binding]:\r\n    return read_bindings_csv(Path(path).read_text(encoding=encoding))\r\n# end::binding_read[]\r\n\r\n# tag::xml_path[]\r\ndef normalize_xpath(xpath: str) -&gt; str:\r\n    \"\"\"XPath \u6587\u5b57\u5217\u306e\u524d\u5f8c\u7a7a\u767d\u3092\u9664\u304d\u3001\u9014\u4e2d\u306b\u7a7a\u767d\u304c\u5165\u3063\u3066\u3044\u306a\u3044\u3053\u3068\u3092\u78ba\u8a8d\u3057\u307e\u3059\u3002\"\"\"\r\n    xpath = xpath.strip()\r\n    if re.search(r\"\\s\", xpath):\r\n        raise ValueError(f\"XPath contains whitespace: {xpath!r}\")\r\n    return xpath\r\n\r\n\r\ndef split_attr_path(xpath: str) -&gt; tuple[str, str | None]:\r\n    xpath = normalize_xpath(xpath)\r\n    if \"\/@\" in xpath:\r\n        elem_path, attr_name = xpath.rsplit(\"\/@\", 1)\r\n        return elem_path, attr_name\r\n    return xpath, None\r\n\r\n\r\ndef path_parts(xpath: str) -&gt; list[str]:\r\n    elem_path, _ = split_attr_path(xpath)\r\n    return [p for p in elem_path.split(\"\/\") if p]\r\n\r\n\r\ndef ensure_path(root: ET.Element, xpath: str) -&gt; ET.Element:\r\n    elem_path, _ = split_attr_path(xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    if not parts or parts[0] != \"Invoice\":\r\n        raise ValueError(f\"XPath must start with \/Invoice: {xpath}\")\r\n\r\n    elem = root\r\n    for part in parts[1:]:\r\n        tag = qname(part)\r\n        child = elem.find(tag)\r\n        if child is None:\r\n            child = ET.SubElement(elem, tag)\r\n        elem = child\r\n    return elem\r\n\r\n\r\ndef ensure_relative_path(root: ET.Element, rel_xpath: str) -&gt; ET.Element:\r\n    elem_path, _ = split_attr_path(rel_xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    elem = root\r\n    for part in parts:\r\n        tag = qname(part)\r\n        child = elem.find(tag)\r\n        if child is None:\r\n            child = ET.SubElement(elem, tag)\r\n        elem = child\r\n    return elem\r\n\r\n\r\ndef set_text(root: ET.Element, xpath: str, value: str | None) -&gt; None:\r\n    if value in (None, \"\"):\r\n        return\r\n    elem_path, attr_name = split_attr_path(xpath)\r\n    elem = ensure_path(root, elem_path)\r\n    if attr_name:\r\n        elem.set(attr_name, str(value))\r\n    else:\r\n        elem.text = str(value)\r\n\r\n\r\ndef set_text_relative(root: ET.Element, rel_xpath: str, value: str | None) -&gt; None:\r\n    if value in (None, \"\"):\r\n        return\r\n    elem_path, attr_name = split_attr_path(rel_xpath)\r\n    elem = ensure_relative_path(root, elem_path)\r\n    if attr_name:\r\n        elem.set(attr_name, str(value))\r\n    else:\r\n        elem.text = str(value)\r\n\r\n\r\ndef get_text(root: ET.Element, xpath: str) -&gt; str:\r\n    elem_path, attr_name = split_attr_path(xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    if not parts or parts[0] != \"Invoice\":\r\n        raise ValueError(f\"XPath must start with \/Invoice: {xpath}\")\r\n    elem = root\r\n    for part in parts[1:]:\r\n        elem = elem.find(qname(part))\r\n        if elem is None:\r\n            return \"\"\r\n    if attr_name:\r\n        return elem.attrib.get(attr_name, \"\")\r\n    return elem.text or \"\"\r\n\r\n\r\ndef get_text_relative(root: ET.Element, rel_xpath: str) -&gt; str:\r\n    elem_path, attr_name = split_attr_path(rel_xpath)\r\n    parts = [p for p in elem_path.split(\"\/\") if p]\r\n    elem = root\r\n    for part in parts:\r\n        elem = elem.find(qname(part))\r\n        if elem is None:\r\n            return \"\"\r\n    if attr_name:\r\n        return elem.attrib.get(attr_name, \"\")\r\n    return elem.text or \"\"\r\n# end::xml_path[]\r\n\r\n# tag::semantic_path[]\r\ndef rows_by_dimension(rows: list[dict[str, str]], dimension: str, d_invoice: str = \"1\") -&gt; list[dict[str, str]]:\r\n    \"\"\"dXXX \u306b\u5024\u304c\u3042\u308b\u884c\u3060\u3051\u3092\u96c6\u3081\u3001\u305d\u306e\u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3\u968e\u5c64\u306e\u884c\u96c6\u5408\u3092\u8fd4\u3057\u307e\u3059\u3002\"\"\"\r\n    return [r for r in rows if r.get(\"dInvoice\") == d_invoice and r.get(dimension)]\r\n\r\n\r\ndef first_value(rows: list[dict[str, str]], column: str, d_invoice: str = \"1\") -&gt; str:\r\n    for row in rows:\r\n        if row.get(\"dInvoice\") == d_invoice and row.get(column):\r\n            return row[column]\r\n    return \"\"\r\n\r\n\r\ndef direct_dimension_target(path: str) -&gt; tuple[str, str] | None:\r\n    \"\"\"$.Invoice.dTaxBreakdown.taxAmount \u306e\u3088\u3046\u306a\u3001dXXX \u76f4\u4e0b\u306e\u9805\u76ee\u5b9a\u7fa9\u3092\u5224\u5b9a\u3057\u307e\u3059\u3002\"\"\"\r\n    m = re.fullmatch(r\"\\$\\.Invoice\\.(d[A-Za-z_][A-Za-z0-9_]*)\\.([A-Za-z_][A-Za-z0-9_]*)\", path)\r\n    if not m:\r\n        return None\r\n    return m.group(1), m.group(2)\r\n\r\n\r\ndef query_semantic_path(\r\n    rows: list[dict[str, str]],\r\n    path: str,\r\n    d_invoice: str = \"1\",\r\n    current_row: dict[str, str] | None = None,\r\n) -&gt; str:\r\n    \"\"\"\r\n    \u6271\u3046 SemanticPath subset:\r\n      const:VALUE\r\n      $.Invoice.field\r\n      $.Invoice.dDimension.field\r\n      $.Invoice.dimension[?@.filterField=\"filterValue\"].field\r\n      $.Invoice.dimension[?@.filterField=filterValue].field\r\n    \"\"\"\r\n    if path.startswith(\"const:\"):\r\n        return path.split(\":\", 1)[1]\r\n\r\n    m = re.fullmatch(r\"\\$\\.Invoice\\.([A-Za-z_][A-Za-z0-9_]*)\", path)\r\n    if m:\r\n        return first_value(rows, m.group(1), d_invoice)\r\n\r\n    dim_target = direct_dimension_target(path)\r\n    if dim_target:\r\n        dimension, target_field = dim_target\r\n        if current_row is not None and current_row.get(dimension):\r\n            return current_row.get(target_field, \"\")\r\n        repeated_rows = rows_by_dimension(rows, dimension, d_invoice)\r\n        if repeated_rows:\r\n            return repeated_rows[0].get(target_field, \"\")\r\n        return \"\"\r\n\r\n    m = re.fullmatch(\r\n        r\"\\$\\.Invoice\\.([A-Za-z_][A-Za-z0-9_]*)\"\r\n        r\"\\[\\?@\\.([A-Za-z_][A-Za-z0-9_]*)=(?:\\\"([^\\\"]+)\\\"|([^\\]]+))\\]\"\r\n        r\"\\.([A-Za-z_][A-Za-z0-9_]*)\",\r\n        path,\r\n    )\r\n    if m:\r\n        dimension, filter_field, quoted_value, bare_value, target_field = m.groups()\r\n        filter_value = quoted_value if quoted_value is not None else bare_value\r\n        for row in rows_by_dimension(rows, dimension, d_invoice):\r\n            if row.get(filter_field) == filter_value:\r\n                return row.get(target_field, \"\")\r\n        return \"\"\r\n\r\n    raise ValueError(f\"Unsupported SemanticPath: {path}\")\r\n# end::semantic_path[]\r\n\r\ndef scalar_bindings(bindings: list[Binding], repeat_defs: dict[str, str]) -&gt; list[Binding]:\r\n    repeated_paths = tuple(repeat_defs.values())\r\n    result: list[Binding] = []\r\n    for semantic_path, xpath in bindings:\r\n        elem_path, _ = split_attr_path(xpath)\r\n        if any(elem_path.startswith(repeat_path + \"\/\") for repeat_path in repeated_paths):\r\n            continue\r\n        result.append((semantic_path, xpath))\r\n    return result\r\n\r\n\r\ndef common_path_prefix(paths: list[str]) -&gt; str:\r\n    split_paths = [path_parts(p) for p in paths]\r\n    if not split_paths:\r\n        return \"\"\r\n    prefix = split_paths[0]\r\n    for parts in split_paths[1:]:\r\n        max_len = min(len(prefix), len(parts))\r\n        i = 0\r\n        while i &lt; max_len and prefix[i] == parts[i]:\r\n            i += 1\r\n        prefix = prefix[:i]\r\n        if not prefix:\r\n            break\r\n    return \"\/\" + \"\/\".join(prefix) if prefix else \"\"\r\n\r\n\r\ndef infer_repeat_definitions(bindings: list[Binding]) -&gt; dict[str, str]:\r\n    \"\"\"dXXX \u306e XPath \u7fa4\u304b\u3089\u3001\u305d\u306e\u30c7\u30a3\u30e1\u30f3\u30b7\u30e7\u30f3\u304c\u5bfe\u5fdc\u3059\u308b\u7e70\u8fd4\u3057 XML \u968e\u5c64\u3092\u63a8\u5b9a\u3057\u307e\u3059\u3002\"\"\"\r\n    by_dimension: dict[str, list[str]] = {}\r\n    for semantic_path, xpath in bindings:\r\n        dim_target = direct_dimension_target(semantic_path)\r\n        if not dim_target:\r\n            continue\r\n        dimension, _ = dim_target\r\n        by_dimension.setdefault(dimension, []).append(xpath)\r\n\r\n    repeat_defs: dict[str, str] = {}\r\n    for dimension, xpaths in by_dimension.items():\r\n        repeat_path = common_path_prefix(xpaths)\r\n        if repeat_path and repeat_path != \"\/Invoice\":\r\n            repeat_defs[dimension] = repeat_path\r\n    return repeat_defs\r\n\r\n\r\ndef bindings_for_repeat_path(bindings: list[Binding], repeat_path: str) -&gt; list[Binding]:\r\n    result: list[Binding] = []\r\n    for semantic_path, xpath in bindings:\r\n        elem_path, _ = split_attr_path(xpath)\r\n        if elem_path.startswith(repeat_path + \"\/\"):\r\n            result.append((semantic_path, xpath))\r\n    return result\r\n\r\n\r\n# tag::tax_total[]\r\ndef apply_repeating_section(\r\n    invoice: ET.Element,\r\n    rows: list[dict[str, str]],\r\n    bindings: list[Binding],\r\n    dimension: str,\r\n    repeat_path: str,\r\n    d_invoice: str = \"1\",\r\n) -&gt; None:\r\n    # \u540c\u3058\u7e70\u8fd4\u3057\u968e\u5c64\u306b\u5c5e\u3059\u308b binding \u7fa4\u3092\u96c6\u3081\u308b\r\n    section_bindings = bindings_for_repeat_path(bindings, repeat_path)\r\n    if not section_bindings:\r\n        return\r\n\r\n    repeat_rows = rows_by_dimension(rows, dimension, d_invoice)\r\n    if not repeat_rows:\r\n        return\r\n\r\n    repeat_parts = path_parts(repeat_path)\r\n    if len(repeat_parts) &lt; 2 or repeat_parts[0] != \"Invoice\":\r\n        raise ValueError(f\"Invalid repeat path: {repeat_path}\")\r\n\r\n    container_path = \"\/\" + \"\/\".join(repeat_parts[:-1])\r\n    repeat_tag = repeat_parts[-1]\r\n    container = ensure_path(invoice, container_path)\r\n\r\n    marker_path = repeat_path + \"\/\"\r\n    # dXXX \u3054\u3068\u306e\u5404\u884c\u3092\u3001\u5bfe\u5fdc\u3059\u308b XML \u306e\u53cd\u5fa9\u8981\u7d20\u3068\u3057\u3066\u51fa\u529b\u3059\u308b\r\n    for repeat_row in repeat_rows:\r\n        repeat_elem = ET.SubElement(container, qname(repeat_tag))\r\n        for semantic_path, xpath in section_bindings:\r\n            _, suffix = xpath.split(marker_path, 1)\r\n            value = query_semantic_path(rows, semantic_path, d_invoice, current_row=repeat_row)\r\n            set_text_relative(repeat_elem, suffix, value)\r\n# end::tax_total[]\r\n\r\n# tag::csv_to_xml[]\r\ndef csv_to_ubl_xml(rows: list[dict[str, str]], bindings: list[Binding], d_invoice: str = \"1\") -&gt; ET.Element:\r\n    \"\"\"\u69cb\u9020\u5316CSV\u3092 XML \u3078\u5909\u63db\u3057\u307e\u3059\u3002\u5358\u4e00\u9805\u76ee\u306f binding \u3067\u3001\u660e\u7d30\u884c\u306f\u88dc\u52a9\u51e6\u7406\u3067\u51fa\u529b\u3057\u307e\u3059\u3002\"\"\"\r\n    invoice = ET.Element(qname(\"Invoice\"))\r\n    # binding \u5b9a\u7fa9\u3092\u898b\u3066\u3001dXXX \u306b\u5bfe\u5fdc\u3059\u308b XML \u306e\u53cd\u5fa9\u968e\u5c64\u3092\u7279\u5b9a\u3059\u308b\r\n    repeat_defs = infer_repeat_definitions(bindings)\r\n\r\n    for semantic_path, xpath in scalar_bindings(bindings, repeat_defs):\r\n        value = query_semantic_path(rows, semantic_path, d_invoice)\r\n        set_text(invoice, xpath, value)\r\n\r\n    for dimension, repeat_path in repeat_defs.items():\r\n        apply_repeating_section(invoice, rows, bindings, dimension, repeat_path, d_invoice)\r\n\r\n    # \u660e\u7d30\u884c\u306f\u3053\u306e\u30b5\u30f3\u30d7\u30eb\u3067\u306f\u88dc\u52a9\u51e6\u7406\u3067\u51fa\u529b\u3057\u3066\u3044\u308b\r\n    append_invoice_lines(invoice, rows, first_value(rows, \"currencyCode\", d_invoice), d_invoice)\r\n    return invoice\r\n# end::csv_to_xml[]\r\n\r\n# tag::invoice_lines[]\r\ndef append_invoice_lines(invoice: ET.Element, rows: list[dict[str, str]], currency: str, d_invoice: str = \"1\") -&gt; None:\r\n    \"\"\"\u8acb\u6c42\u660e\u7d30\u884c\u3092 XML \u3078\u5c55\u958b\u3057\u307e\u3059\u3002\u73fe\u72b6\u306f\u7d50\u5408\u8868\u306e\u5b8c\u5168\u81ea\u52d5\u5316\u5bfe\u8c61\u5916\u3067\u3059\u3002\"\"\"\r\n    for line_row in rows_by_dimension(rows, \"dInvoiceLine\", d_invoice):\r\n        line = ET.SubElement(invoice, qname(\"cac:InvoiceLine\"))\r\n        ET.SubElement(line, qname(\"cbc:ID\")).text = line_row[\"lineID\"]\r\n        ET.SubElement(line, qname(\"cbc:InvoicedQuantity\"), {\"unitCode\": line_row.get(\"unitCode\") or \"EA\"}).text = line_row[\"invoicedQuantity\"]\r\n        ET.SubElement(line, qname(\"cbc:LineExtensionAmount\"), {\"currencyID\": currency}).text = line_row[\"lineExtensionAmount\"]\r\n\r\n        item = ET.SubElement(line, qname(\"cac:Item\"))\r\n        ET.SubElement(item, qname(\"cbc:Name\")).text = line_row[\"itemName\"]\r\n        if line_row.get(\"lineTaxCategoryCode\"):\r\n            tax_category = ET.SubElement(item, qname(\"cac:ClassifiedTaxCategory\"))\r\n            ET.SubElement(tax_category, qname(\"cbc:ID\")).text = line_row[\"lineTaxCategoryCode\"]\r\n            ET.SubElement(tax_category, qname(\"cbc:Percent\")).text = line_row[\"lineTaxRate\"]\r\n            scheme = ET.SubElement(tax_category, qname(\"cac:TaxScheme\"))\r\n            ET.SubElement(scheme, qname(\"cbc:ID\")).text = \"VAT\"\r\n\r\n        price = ET.SubElement(line, qname(\"cac:Price\"))\r\n        ET.SubElement(price, qname(\"cbc:PriceAmount\"), {\"currencyID\": currency}).text = line_row[\"unitPriceAmount\"]\r\n# end::invoice_lines[]\r\n\r\ndef new_empty_row(fieldnames: list[str], d_invoice: str = \"1\") -&gt; dict[str, str]:\r\n    row = {name: \"\" for name in fieldnames}\r\n    row[\"dInvoice\"] = d_invoice\r\n    return row\r\n\r\n\r\n# tag::xml_to_csv[]\r\ndef append_header_row(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    row = new_empty_row(fieldnames, d_invoice)\r\n    row[\"invoiceNumber\"] = get_text(invoice, \"\/Invoice\/cbc:ID\")\r\n    row[\"issueDate\"] = get_text(invoice, \"\/Invoice\/cbc:IssueDate\")\r\n    row[\"invoiceTypeCode\"] = get_text(invoice, \"\/Invoice\/cbc:InvoiceTypeCode\")\r\n    row[\"currencyCode\"] = get_text(invoice, \"\/Invoice\/cbc:DocumentCurrencyCode\")\r\n    row[\"totalTaxAmount\"] = get_text(invoice, \"\/Invoice\/cac:TaxTotal\/cbc:TaxAmount\")\r\n    rows.append(row)\r\n\r\n\r\ndef append_party_rows(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    party_specs = [\r\n        (\"1\", \"Seller\", \"\/Invoice\/cac:AccountingSupplierParty\/cac:Party\"),\r\n        (\"2\", \"Buyer\", \"\/Invoice\/cac:AccountingCustomerParty\/cac:Party\"),\r\n    ]\r\n    for d_party, role, party_xpath in party_specs:\r\n        parts = [p for p in party_xpath.split(\"\/\") if p]\r\n        party = invoice\r\n        for part in parts[1:]:\r\n            party = party.find(qname(part))\r\n            if party is None:\r\n                break\r\n        if party is None:\r\n            continue\r\n        row = new_empty_row(fieldnames, d_invoice)\r\n        row[\"dInvoiceParty\"] = d_party\r\n        row[\"partyRole\"] = role\r\n        name = party.find(f\"{qname('cac:PartyName')}\/{qname('cbc:Name')}\")\r\n        tax_id = party.find(f\"{qname('cac:PartyTaxScheme')}\/{qname('cbc:CompanyID')}\")\r\n        row[\"partyName\"] = name.text if name is not None and name.text else \"\"\r\n        row[\"partyTaxID\"] = tax_id.text if tax_id is not None and tax_id.text else \"\"\r\n        rows.append(row)\r\n\r\n\r\ndef append_document_reference_rows(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    ref_specs = [\r\n        (\"Order\", \"\/Invoice\/cac:OrderReference\/cbc:ID\"),\r\n        (\"Delivery\", \"\/Invoice\/cac:DespatchDocumentReference\/cbc:ID\"),\r\n    ]\r\n    ref_no = 1\r\n    for ref_type, ref_xpath in ref_specs:\r\n        ref_id = get_text(invoice, ref_xpath)\r\n        if ref_id:\r\n            row = new_empty_row(fieldnames, d_invoice)\r\n            row[\"dDocumentReference\"] = str(ref_no)\r\n            row[\"referenceType\"] = ref_type\r\n            row[\"referenceID\"] = ref_id\r\n            rows.append(row)\r\n            ref_no += 1\r\n\r\n\r\ndef append_payment_row(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    due_date = get_text(invoice, \"\/Invoice\/cbc:DueDate\")\r\n    payment_id = get_text(invoice, \"\/Invoice\/cac:PaymentMeans\/cbc:PaymentID\")\r\n    if due_date or payment_id:\r\n        row = new_empty_row(fieldnames, d_invoice)\r\n        row[\"dPayment\"] = \"1\"\r\n        row[\"paymentDueDate\"] = due_date\r\n        row[\"paymentReference\"] = payment_id\r\n        rows.append(row)\r\n\r\n\r\ndef append_repeating_rows_from_bindings(\r\n    rows: list[dict[str, str]],\r\n    invoice: ET.Element,\r\n    fieldnames: list[str],\r\n    bindings: list[Binding],\r\n    d_invoice: str = \"1\",\r\n) -&gt; None:\r\n    # binding \u5b9a\u7fa9\u3092\u898b\u3066\u3001dXXX \u306b\u5bfe\u5fdc\u3059\u308b XML \u306e\u53cd\u5fa9\u968e\u5c64\u3092\u7279\u5b9a\u3059\u308b\r\n    repeat_defs = infer_repeat_definitions(bindings)\r\n    for dimension, repeat_path in repeat_defs.items():\r\n        # \u540c\u3058\u7e70\u8fd4\u3057\u968e\u5c64\u306b\u5c5e\u3059\u308b binding \u7fa4\u3092\u96c6\u3081\u308b\r\n        section_bindings = bindings_for_repeat_path(bindings, repeat_path)\r\n        repeat_parts = path_parts(repeat_path)\r\n        if len(repeat_parts) &lt; 2 or repeat_parts[0] != \"Invoice\":\r\n            continue\r\n\r\n        parent_path = \"\/\" + \"\/\".join(repeat_parts[:-1])\r\n        repeat_tag = repeat_parts[-1]\r\n        parent_elem = invoice\r\n        for part in path_parts(parent_path)[1:]:\r\n            parent_elem = parent_elem.find(qname(part))\r\n            if parent_elem is None:\r\n                break\r\n        if parent_elem is None:\r\n            continue\r\n\r\n        # XML \u5074\u306e\u53cd\u5fa9\u8981\u7d20\u3092\u9806\u306b\u8aad\u307f\u3001\u69cb\u9020\u5316CSV\u306e dXXX \u884c\u3078\u623b\u3059\r\n        repeat_elems = parent_elem.findall(qname(repeat_tag))\r\n        marker_path = repeat_path + \"\/\"\r\n        for i, repeat_elem in enumerate(repeat_elems, start=1):\r\n            row = new_empty_row(fieldnames, d_invoice)\r\n            row[dimension] = str(i)\r\n            for semantic_path, xpath in section_bindings:\r\n                dim_target = direct_dimension_target(semantic_path)\r\n                if not dim_target or dim_target[0] != dimension:\r\n                    continue\r\n                target_field = dim_target[1]\r\n                _, suffix = xpath.split(marker_path, 1)\r\n                row[target_field] = get_text_relative(repeat_elem, suffix)\r\n            rows.append(row)\r\n\r\n\r\ndef append_invoice_line_rows(rows: list[dict[str, str]], invoice: ET.Element, fieldnames: list[str], d_invoice: str = \"1\") -&gt; None:\r\n    for i, line in enumerate(invoice.findall(qname(\"cac:InvoiceLine\")), start=1):\r\n        row = new_empty_row(fieldnames, d_invoice)\r\n        row[\"dInvoiceLine\"] = str(i)\r\n        line_id = line.find(qname(\"cbc:ID\"))\r\n        quantity = line.find(qname(\"cbc:InvoicedQuantity\"))\r\n        line_amount = line.find(qname(\"cbc:LineExtensionAmount\"))\r\n        item = line.find(qname(\"cac:Item\"))\r\n        price = line.find(qname(\"cac:Price\"))\r\n        row[\"lineID\"] = line_id.text if line_id is not None and line_id.text else \"\"\r\n        if quantity is not None:\r\n            row[\"invoicedQuantity\"] = quantity.text or \"\"\r\n            row[\"unitCode\"] = quantity.attrib.get(\"unitCode\", \"\")\r\n        row[\"lineExtensionAmount\"] = line_amount.text if line_amount is not None and line_amount.text else \"\"\r\n        if item is not None:\r\n            name = item.find(qname(\"cbc:Name\"))\r\n            row[\"itemName\"] = name.text if name is not None and name.text else \"\"\r\n            tax_category = item.find(qname(\"cac:ClassifiedTaxCategory\"))\r\n            if tax_category is not None:\r\n                cat_id = tax_category.find(qname(\"cbc:ID\"))\r\n                percent = tax_category.find(qname(\"cbc:Percent\"))\r\n                row[\"lineTaxCategoryCode\"] = cat_id.text if cat_id is not None and cat_id.text else \"\"\r\n                row[\"lineTaxRate\"] = percent.text if percent is not None and percent.text else \"\"\r\n        if price is not None:\r\n            price_amount = price.find(qname(\"cbc:PriceAmount\"))\r\n            row[\"unitPriceAmount\"] = price_amount.text if price_amount is not None and price_amount.text else \"\"\r\n        rows.append(row)\r\n\r\n\r\ndef ubl_xml_to_csv_rows(invoice: ET.Element, fieldnames: list[str], bindings: list[Binding], d_invoice: str = \"1\") -&gt; list[dict[str, str]]:\r\n    \"\"\"XML \u3092\u8aad\u307f\u3001\u69cb\u9020\u5316CSV\u306e\u884c\u30ea\u30b9\u30c8\u3078\u623b\u3057\u307e\u3059\u3002\"\"\"\r\n    rows: list[dict[str, str]] = []\r\n    append_header_row(rows, invoice, fieldnames, d_invoice)\r\n    append_party_rows(rows, invoice, fieldnames, d_invoice)\r\n    append_document_reference_rows(rows, invoice, fieldnames, d_invoice)\r\n    append_payment_row(rows, invoice, fieldnames, d_invoice)\r\n    append_repeating_rows_from_bindings(rows, invoice, fieldnames, bindings, d_invoice)\r\n    append_invoice_line_rows(rows, invoice, fieldnames, d_invoice)\r\n    return rows\r\n# end::xml_to_csv[]\r\n\r\n# tag::output[]\r\ndef rows_to_csv(rows: list[dict[str, str]], fieldnames: list[str]) -&gt; str:\r\n    out = io.StringIO()\r\n    writer = csv.DictWriter(out, fieldnames=fieldnames, lineterminator=\"\\n\")\r\n    writer.writeheader()\r\n    writer.writerows(rows)\r\n    return out.getvalue()\r\n\r\n\r\ndef write_xml(elem: ET.Element, path: str | Path) -&gt; None:\r\n    tree = ET.ElementTree(elem)\r\n    ET.indent(tree, space=\"  \")\r\n    tree.write(path, encoding=\"utf-8\", xml_declaration=True)\r\n# end::output[]\r\n\r\n# tag::main[]\r\ndef main() -&gt; None:\r\n    parser = argparse.ArgumentParser(\r\n        description=\"\u69cb\u9020\u5316CSV\u3068\u7c21\u7565\u5316\u3057\u305f UBL Invoice XML \u306e\u76f8\u4e92\u5909\u63db\u30b5\u30f3\u30d7\u30eb\",\r\n        epilog=\"\u4f8b: py .\\\\syntax_binding.py .\\\\invoice.csv .\\\\bindings.csv --xml-out .\\\\invoice.xml --roundtrip-out .\\\\roundtrip.csv\",\r\n    )\r\n    parser.add_argument(\"invoice_csv\", type=Path, help=\"\u5165\u529b\u3068\u306a\u308b\u69cb\u9020\u5316CSV\u30d5\u30a1\u30a4\u30eb\")\r\n    parser.add_argument(\"bindings_csv\", type=Path, help=\"Semantic path \u3068 XPath \u3092\u5bfe\u5fdc\u4ed8\u3051\u305f binding CSV\")\r\n    parser.add_argument(\"--xml-out\", type=Path, default=Path(\"invoice.xml\"), help=\"\u751f\u6210\u3059\u308b XML \u306e\u51fa\u529b\u5148\")\r\n    parser.add_argument(\"--roundtrip-out\", type=Path, default=Path(\"roundtrip.csv\"), help=\"XML \u3092\u8aad\u307f\u623b\u3057\u3066\u518d\u69cb\u6210\u3057\u305f CSV \u306e\u51fa\u529b\u5148\")\r\n    args = parser.parse_args()\r\n\r\n    # 1) \u5165\u529b CSV \u3068 binding CSV \u3092\u8aad\u3080\r\n    rows = read_core_csv_file(args.invoice_csv)\r\n    bindings = read_bindings_csv_file(args.bindings_csv)\r\n    # 2) CSV -&gt; XML \u5909\u63db\r\n    invoice = csv_to_ubl_xml(rows, bindings)\r\n    write_xml(invoice, args.xml_out)\r\n\r\n    # 3) XML -&gt; CSV \u306e\u9006\u5909\u63db\u3092\u884c\u3044\u3001roundtrip.csv \u3092\u51fa\u529b\u3059\u308b\r\n    fieldnames = list(rows[0].keys()) if rows else []\r\n    roundtrip_rows = ubl_xml_to_csv_rows(invoice, fieldnames, bindings)\r\n    args.roundtrip_out.write_text(rows_to_csv(roundtrip_rows, fieldnames), encoding=\"utf-8\")\r\n# end::main[]\r\n\r\nif __name__ == \"__main__\":\r\n    main()<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div id=\"footer\">\n<div id=\"footer-text\">Last updated 2026-07-02 14:44:38 +0900<\/div>\n<\/div>\n<div id=\"toc\" class=\"toc2\">\n<div id=\"toctitle\">Table of Contents<\/div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#_\u306f\u3058\u3081\u306b\">1. \u306f\u3058\u3081\u306b<\/a><\/li>\n<li><a href=\"#_\u30d5\u30a1\u30a4\u30eb\u69cb\u6210\">2. \u30d5\u30a1\u30a4\u30eb\u69cb\u6210<\/a><\/li>\n<li><a href=\"#_\u69cb\u9020\u5316csv\u3068\u69cb\u6587\u7d50\u5408\u8868\">3. \u69cb\u9020\u5316CSV\u3068\u69cb\u6587\u7d50\u5408\u8868<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_\u69cb\u9020\u5316csv\u306e\u4f8b\">3.1. \u69cb\u9020\u5316CSV\u306e\u4f8b<\/a><\/li>\n<li><a href=\"#_\u69cb\u6587\u7d50\u5408\u8868csv\">3.2. \u69cb\u6587\u7d50\u5408\u8868CSV<\/a><\/li>\n<li><a href=\"#_bindings_csv_\u306e\u5b9a\u7fa9\u65b9\u6cd5\">3.3. bindings.csv \u306e\u5b9a\u7fa9\u65b9\u6cd5<\/a><\/li>\n<li><a href=\"#_dxxx_\u3068_cacxxx_cbczzz_\u306e\u5bfe\u5fdc\">3.4. dXXX \u3068 cac:XXX \/ cbc:ZZZ \u306e\u5bfe\u5fdc<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_python\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5168\u4f53\u69cb\u6210\">4. Python\u30d7\u30ed\u30b0\u30e9\u30e0\u306e\u5168\u4f53\u69cb\u6210<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_csv\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3080\">4.1. CSV\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3080<\/a><\/li>\n<li><a href=\"#_\u69cb\u6587\u7d50\u5408\u8868csv\u3092\u8aad\u307f\u8fbc\u3080\">4.2. \u69cb\u6587\u7d50\u5408\u8868CSV\u3092\u8aad\u307f\u8fbc\u3080<\/a><\/li>\n<li><a href=\"#_semanticpath\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b\">4.3. SemanticPath\u3067\u5024\u3092\u53d6\u5f97\u3059\u308b<\/a><\/li>\n<li><a href=\"#_elementtree\u3067xml\u3092\u6271\u3046\">4.4. ElementTree\u3067XML\u3092\u6271\u3046<\/a><\/li>\n<li><a href=\"#_xpath\u306b\u6cbf\u3063\u3066\u8981\u7d20\u3092\u751f\u6210\u3059\u308b\">4.5. XPath\u306b\u6cbf\u3063\u3066\u8981\u7d20\u3092\u751f\u6210\u3059\u308b<\/a><\/li>\n<li><a href=\"#_\u69cb\u6587\u7d50\u5408\u8868\u3092\u4f7f\u3063\u3066csv\u304b\u3089xml\u3092\u4f5c\u308b\">4.6. \u69cb\u6587\u7d50\u5408\u8868\u3092\u4f7f\u3063\u3066CSV\u304b\u3089XML\u3092\u4f5c\u308b<\/a><\/li>\n<li><a href=\"#_\u7e70\u8fd4\u3057\u69cb\u9020\u306e\u6271\u3044\">4.7. \u7e70\u8fd4\u3057\u69cb\u9020\u306e\u6271\u3044<\/a><\/li>\n<li><a href=\"#_\u7a0e\u7387\u5225\u5185\u8a33\u3092xml\u3078\u5909\u63db\u3059\u308b\">4.8. \u7a0e\u7387\u5225\u5185\u8a33\u3092XML\u3078\u5909\u63db\u3059\u308b<\/a><\/li>\n<li><a href=\"#_\u8acb\u6c42\u660e\u7d30\u3092xml\u3078\u5909\u63db\u3059\u308b\">4.9. \u8acb\u6c42\u660e\u7d30\u3092XML\u3078\u5909\u63db\u3059\u308b<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_xml\u304b\u3089csv\u3092\u751f\u6210\u3059\u308b\">5. XML\u304b\u3089CSV\u3092\u751f\u6210\u3059\u308b<\/a><\/li>\n<li><a href=\"#_\u51fa\u529b\u51e6\u7406\u3068main\u95a2\u6570\">6. \u51fa\u529b\u51e6\u7406\u3068main\u95a2\u6570<\/a><\/li>\n<li><a href=\"#_\u5b9f\u884c\u7d50\u679c\">7. \u5b9f\u884c\u7d50\u679c<\/a><\/li>\n<li><a href=\"#_\u30d7\u30ed\u30b0\u30e9\u30de\u5411\u3051\u88dc\u8db3\">8. \u30d7\u30ed\u30b0\u30e9\u30de\u5411\u3051\u88dc\u8db3<\/a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_\u306a\u305c\u69cb\u6587\u7d50\u5408\u8868\u3092csv\u306b\u51fa\u3059\u306e\u304b\">8.1. \u306a\u305c\u69cb\u6587\u7d50\u5408\u8868\u3092CSV\u306b\u51fa\u3059\u306e\u304b<\/a><\/li>\n<li><a href=\"#_\u9650\u5b9a\u3055\u308c\u305fsemanticpath_subset\">8.2. \u9650\u5b9a\u3055\u308c\u305fSemanticPath subset<\/a><\/li>\n<li><a href=\"#_\u7e70\u8fd4\u3057\u69cb\u9020\u306f\u5225\u898f\u5247\u306b\u3057\u3066\u3044\u308b\">8.3. \u7e70\u8fd4\u3057\u69cb\u9020\u306f\u5225\u898f\u5247\u306b\u3057\u3066\u3044\u308b<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#_\u304a\u308f\u308a\u306b\">9. \u304a\u308f\u308a\u306b<\/a><\/li>\n<li><a href=\"#_\u53c2\u8003\u30b5\u30f3\u30d7\u30eb\u30bd\u30fc\u30b9\">10. \u53c2\u8003\uff1a\u30b5\u30f3\u30d7\u30eb\u30bd\u30fc\u30b9<\/a><\/li>\n<\/ul>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Views: 2 \u69cb\u6587\u7d50\u5408\u8868CSV\u3067\u5b9f\u73fe\u3059\u308b\u69cb\u9020\u5316CSV\u3068JP PINT UBL\u306e\u76f8\u4e92\u5909\u63db ChatGPT\uff08\u7de8\u96c6\u3000\u4e09\u5206\u4e00\u4fe1\u4e4b\uff09 2026-07-02 1. \u306f\u3058\u3081\u306b \u524d\u56de\u306e\u8a18\u4e8b\u3067\u306f\uff0c\u65e5\u672c\u7248\u30b3\u30a2\u30a4\u30f3\u30dc\u30a4\u30b9\u3092\u69cb\u9020\u5316CSV\u3068\u3057 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":17094,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[21,45,49,68,77],"tags":[],"_links":{"self":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/17102"}],"collection":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=17102"}],"version-history":[{"count":10,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/17102\/revisions"}],"predecessor-version":[{"id":17117,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/posts\/17102\/revisions\/17117"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=\/wp\/v2\/media\/17094"}],"wp:attachment":[{"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=17102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=17102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sambuichi.jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=17102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}