diff --git a/ChangeLog b/ChangeLog index 63f03b11ef..d77d2cfa1b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-02-04 Joshua Sled + + * src/doc/xml/gnucash-v2.rnc: Add reverse-engineered schema for + "v2" (1.8/2.0) XML files. + + * src/backend/file/io-gncxml-v2.c (write_v2_header): Emit + 'fs' (FreqSpec), 'bgt', 'recurrence' (Budgeting), and 'lot' + namespace decls. + 2006-02-04 David Hampton * src/import-export/schemas/Makefile.am: diff --git a/src/backend/file/io-gncxml-v2.c b/src/backend/file/io-gncxml-v2.c index 6a9f296d09..36244d6de0 100644 --- a/src/backend/file/io-gncxml-v2.c +++ b/src/backend/file/io-gncxml-v2.c @@ -1116,6 +1116,10 @@ write_v2_header (FILE *out) gnc_xml2_write_namespace_decl (out, "sx"); gnc_xml2_write_namespace_decl (out, "trn"); gnc_xml2_write_namespace_decl (out, "ts"); + gnc_xml2_write_namespace_decl (out, "fs"); + gnc_xml2_write_namespace_decl (out, "bgt"); + gnc_xml2_write_namespace_decl (out, "recurrence"); + gnc_xml2_write_namespace_decl (out, "lot"); /* now cope with the plugins */ qof_object_foreach_backend (GNC_FILE_BACKEND, do_write_namespace_cb, out); diff --git a/src/doc/xml/gnucash-v2.rnc b/src/doc/xml/gnucash-v2.rnc new file mode 100644 index 0000000000..e67c1c46e6 --- /dev/null +++ b/src/doc/xml/gnucash-v2.rnc @@ -0,0 +1,406 @@ +# Feb 2006: A RELAX NG Compact schema for gnucash "v2" XML files. +# Copyright (C) 2006 Joshua Sled + +# This schema is non-normative; files emitted by gnucash <= 2.0 (and perhaps +# later) that do not validate against it likely represent a problem with the +# schema, not the file. + +# http://relaxng.org/compact-tutorial-20030326.html + +namespace gnc = "http://www.gnucash.org/XML/gnc" +namespace act = "http://www.gnucash.org/XML/act" +namespace book = "http://www.gnucash.org/XML/book" +namespace cd = "http://www.gnucash.org/XML/cd" +namespace cmdty = "http://www.gnucash.org/XML/cmdty" +namespace price = "http://www.gnucash.org/XML/price" +namespace slot = "http://www.gnucash.org/XML/slot" +namespace split = "http://www.gnucash.org/XML/split" +namespace sx = "http://www.gnucash.org/XML/sx" +namespace trn = "http://www.gnucash.org/XML/trn" +namespace ts = "http://www.gnucash.org/XML/ts" +namespace cust = "http://www.gnucash.org/XML/cust" +namespace job = "http://www.gnucash.org/XML/job" +namespace addr = "http://www.gnucash.org/XML/addr" +namespace owner = "http://www.gnucash.org/XML/owner" +namespace taxtable = "http://www.gnucash.org/XML/taxtable" +namespace tte = "http://www.gnucash.org/XML/tte" +namespace employee = "http://www.gnucash.org/XML/employee" +namespace order = "http://www.gnucash.org/XML/order" +namespace billterm = "http://www.gnucash.org/XML/billterm" +namespace bt-days = "http://www.gnucash.org/XML/bt-days" +namespace bt-prox = "http://www.gnucash.org/XML/bt-prox" +namespace invoice = "http://www.gnucash.org/XML/invoice" +namespace entry = "http://www.gnucash.org/XML/entry" +namespace vendor = "http://www.gnucash.org/XML/vendor" +namespace lot = "http://www.gnucash.org/XML/lot" +namespace fs = "http://www.gnucash.org/XML/fs" +namespace bgt = "http://www.gnucash.org/XML/bgt" +namespace recurrence = "http://www.gnucash.org/XML/recurrence" + +start = GnuCashXml + +GnuCashXml = element gnc-v2 { + element gnc:count-data { attribute cd:type { "book" }, xsd:int }, + Book +} + +Book = element gnc:book { + attribute version { "2.0.0" }, + element book:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element book:slots { KvpSlot+ }?, + element gnc:count-data { attribute cd:type { "commodity" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "account" }, xsd:int }, + element gnc:count-data { attribute cd:type { "transaction" }, xsd:int }, + element gnc:count-data { attribute cd:type { "schedxaction" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "budget" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "gnc:GncCustomer" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "gnc:GncEmployee" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "gnc:GncBillTerm" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "gnc:GncInvoice" }, xsd:int }?, + element gnc:count-data { attribute cd:type { "gnc:GncEntry" }, xsd:int }?, + Commodity*, + PriceDb?, + Account*, + Transaction*, + Customer*, + Employee*, + BillTerm*, + Invoice*, + Entry*, + TemplateTransactions*, + ScheduledTransaction*, + Budget* +} + +Commodity = element gnc:commodity { + attribute version { "2.0.0" }, + element cmdty:space { text }, + element cmdty:id { text }, + element cmdty:name { text }, + element cmdty:fraction { text } +} + +PriceDb = element gnc:pricedb { + attribute version { "1" }, + Price+ +} + +Price = element price { + element price:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element price:commodity { + element cmdty:space { text }, + element cmdty:id { text } + }, + element price:currency { + element cmdty:space { text }, + element cmdty:id { text } + }, + element price:time { TimeStamp }, + element price:source { text }, + # dialog-price-editor.c:type_index_to_string... + element price:type { "bid" | "ask" | "last" | "nav" | "unknown" }, + element price:value { text } +} + +TimeStamp = element ts:date { xsd:string { pattern = "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} -[0-9]{4}" } } + +Account = element gnc:account { + attribute version { "2.0.0" }, + element act:name { text }, + element act:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element act:type { "NO_TYPE" + | "BANK" + | "CASH" + | "CREDIT" + | "ASSET" + | "LIABILITY" + | "STOCK" + | "MUTUAL" + | "CURRENCY" + | "INCOME" + | "EXPENSE" + | "EQUITY" + | "RECEIVABLE" + | "PAYABLE" + | "CHECKING" + | "SAVINGS" + | "MONEYMRKT" + | "CREDITLINE" }, + element act:commodity { + element cmdty:space { text }, + element cmdty:id { text } + }, + element act:commodity-scu { xsd:int }, + element act:code { text }?, + element act:non-standard-scu {empty}?, + element act:description { text }?, + element act:slots { KvpSlot+ }?, + element act:parent { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}?, + element act:lots { Lot+ }? +} + +Lot = element gnc:lot { + attribute version { "2.0.0" }, + element lot:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element lot:slots { KvpSlot+ } +} + +KvpSlot = element slot { + element slot:key { text }, + ( element slot:value { attribute type { "frame" }, KvpSlot+ } + | element slot:value { attribute type { "integer" }, xsd:int } + | element slot:value { attribute type { "double" }, xsd:double } + | element slot:value { attribute type { "numeric" }, xsd:string { pattern = "-?[0-9]+/[0-9]+" } } + | element slot:value { attribute type { "string" }, text } + | element slot:value { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }} + | element slot:value { attribute type { "timespec" }, TimeStamp } + | element slot:value { attribute type { "binary" }, xsd:string { pattern = "[0-9a-f]*" }} + ) +} + +Transaction = element gnc:transaction { + attribute version { "2.0.0" }, + element trn:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element trn:currency { + element cmdty:space { text }, + element cmdty:id { text } + }?, + element trn:num { text }?, + element trn:date-posted { TimeStamp }, + element trn:date-entered { TimeStamp, element ts:ns { xsd:int }? }, + element trn:description { text }, + element trn:slots { KvpSlot+ }?, + element trn:splits { Split+ } +} + +Split = element trn:split { + element split:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element split:memo { text }?, + # this is actually pretty constrained, but... + element split:action { text }?, + element split:reconciled-state { "y" | "n" | "c" }, + element split:reconcile-date { TimeStamp }?, + element split:value { text }?, + element split:quantity { text }, + element split:account { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element split:slots { KvpSlot+ }?, + element split:lot { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}? +} + +Customer = element gnc:GncCustomer { + attribute version { "2.0.0" }, + element cust:guid { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element cust:name { text }, + element cust:id { text }, + element cust:addr { + attribute version { "2.0.0" }, + element addr:name { text }?, + element addr:addr1 { text }?, + element addr:addr2 { text }?, + element addr:addr3 { text }?, + element addr:phone { text }?, + element addr:fax { text }?, + element addr:email { text }? + }, + element cust:shipaddr { + attribute version { "2.0.0" }, + ( empty + | ( element addr:name { text }?, + element addr:addr1 { text }?, + element addr:addr2 { text }?, + element addr:addr3 { text }?, + element addr:phone { text }?, + element addr:fax { text }?, + element addr:email { text }? + ) + ) + }, + element cust:terms { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}?, + # gncTaxTable.c:gncTaxIncludedTypeToString... + element cust:taxincluded { "YES" | "NO" | "USEGLOBAL"}, + element cust:active { xsd:boolean { pattern = "[01]" } }, + element cust:discount { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }, + element cust:credit { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }, + element cust:currency { + element cmdty:space { text }, + element cmdty:id { text } + }, + element cust:use-tt { xsd:boolean { pattern = "[01]" } } +} + +Employee = element gnc:GncEmployee { + attribute version { "2.0.0" }, + element employee:guid { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element employee:username { text }, + element employee:id { text }, + element employee:addr { + attribute version { "2.0.0" }, + element addr:name { text }?, + element addr:addr1 { text }, + element addr:addr2 { text }?, + element addr:addr3 { text }?, + element addr:phone { text }?, + element addr:fax { text }?, + element addr:email { text }? + }, + element employee:active { xsd:boolean { pattern = "[01]" } }, + element employee:workday { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }, + element employee:rate { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }, + element employee:currency { + element cmdty:space { text }, + element cmdty:id { text } + }, + element employee:ccard { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }} +} + +BillTerm = element gnc:GncBillTerm { + attribute version { "2.0.0" }, + element billterm:guid { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element billterm:name { text }, + element billterm:desc { text }, + element billterm:refcount { xsd:int }, + element billterm:invisible { xsd:boolean { pattern = "[01]" } }, + element billterm:child { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}?, + element billterm:parent { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}?, + element billterm:days { + element bt-days:due-days { xsd:int } + } +} + +Invoice = element gnc:GncInvoice { + attribute version { "2.0.0" }, + element invoice:guid { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element invoice:id { text }, # 0-padded xsd:int + element invoice:owner { + attribute version { "2.0.0" }, + element owner:type { text }, # constrained? + element owner:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }} + }, + element invoice:opened { TimeStamp }, + element invoice:posted { TimeStamp }, + element invoice:terms { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}?, + element invoice:billing_id { text }?, + element invoice:notes { text }?, + element invoice:active { xsd:boolean { pattern = "[01]" } }, + element invoice:posttxn { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element invoice:postlot { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element invoice:postacc { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element invoice:currency { + element cmdty:space { text }, + element cmdty:id { text } + }, + element invoice:billto { + attribute version { "2.0.0" }, + element owner:type { "gncCustomer" }, + element owner:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }} + }?, + element invoice:charge-amt { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }? +} + +Entry = element gnc:GncEntry { + attribute version { "2.0.0" }, + element entry:guid { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element entry:date { TimeStamp }, + element entry:entered { TimeStamp }, + element entry:description { text }, + element entry:action { text }?, # probably constrained + element entry:qty { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }, + + ( element entry:i-acct { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element entry:i-price { xsd:string { pattern = "-?[0-9]+/[0-9]+" } }, + element entry:invoice { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + # gncTaxTable.c:gncAmountTypeToString... + element entry:i-disc-type { "VALUE" | "PERCENT" }, + # gncEntry.c:gncEntryDiscountHowToString... + element entry:i-disc-how { "PRETAX" | "POSTTAX" | "SAMETIME" }, + element entry:i-taxable { xsd:boolean { pattern = "[01]" } }, + element entry:i-taxincluded { xsd:boolean { pattern = "[01]" } } + )?, + ( element entry:b-acct { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element entry:b-price { xsd:string { pattern = "-?[0-9]+/[0-9]+" }}, + element entry:bill { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element entry:billable { xsd:boolean { pattern = "[01]" } }, + element entry:b-taxable { xsd:boolean { pattern = "[01]" } }, + element entry:b-taxincluded { xsd:boolean { pattern = "[01]" } }, + # gncEntry.c:gncEntryPaymentTypeToString... + element entry:b-pay { "CASH" | "CARD" } + )? +} + +TemplateTransactions = element gnc:template-transactions { + Account+, + Transaction+ +} + +ScheduledTransaction = element gnc:schedxaction { + attribute version { "1.0.0" }, + element sx:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element sx:name { text }, + element sx:autoCreate { "y" | "n" }, + element sx:autoCreateNotify { "y" | "n" }, + element sx:advanceCreateDays { xsd:int }, + element sx:advanceRemindDays { xsd:int }, + element sx:instanceCount { xsd:int }, + element sx:start { GDate }, + element sx:templ-acct { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element sx:freqspec { GncFreqSpec } +} + +GDate = element gdate { xsd:string { pattern = "[0-9]{4}-[0-9]{2}-[0-9]{2}" } } + +GncFreqSpec = element gnc:freqspec { + attribute version { "1.0.0" }, + element fs:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + # gnc-freqspec-xml-v2.c:gnc_freqSpec_dom_tree_create + element fs:ui_type { "none" + | "once" + | "daily" + | "daily_mf" + | "weekly" + | "bi_weekly" + | "semi_monthly" + | "monthly" + | "quarterly" + | "tri_anually" + | "semi_yearly" + | "yearly" }, + ( element fs:none { empty } + | element fs:once { element fs:date { GDate } } + | element fs:daily { + element fs:interval { xsd:int }, + element fs:offset { xsd:int } + } + | element fs:weekly { + element fs:interval { xsd:int }, + element fs:offset { xsd:int } + } + | element fs:monthly { + element fs:interval { xsd:int }, + element fs:offset { xsd:int }, + element fs:day { xsd:int } + } + | element fs:month_relative { + element fs:interval { xsd:int }, + element fs:offset { xsd:int }, + element fs:weekday { xsd:int }, + element fs:occurrence { xsd:int } + } + | element fs:composite { GncFreqSpec+ } + ) +} + +Budget = element gnc:budget { + attribute version { "2.0.0" }, + element bgt:id { attribute type { "guid" }, xsd:string { pattern = "[0-9a-f]{32}" }}, + element bgt:name { text }, + element bgt:description { text }, + element bgt:num-periods { xsd:int }, + element bgt:recurrence { + attribute version { "1.0.0" }, + element recurrence:mult { xsd:int }, + # Recurrence.c:period_type_strings... + element recurrence:period_type { "once" | "day" | "week" | "month" | "end of month" | "nth weekday" | "last weekday" | "year" }, + element recurrence:start { GDate } + }, + element bgt:slots { KvpSlot+ } +}