假设我有以下格式的数据结构
-----------
MovementOfGoods
---| 4.2. MovementOfGoods : N/A
------| 4.2.1. NumberOfMovementLines : Inteiro *
------| 4.2.2. TotalQuantityIssued : Decimal *
------| 4.2.3. StockMovement : N/A
---------| 4.2.3.1. DocumentNumber : Texto 60 *
---------| 4.2.3.2. ATCUD : Texto 100 *
---------| 4.2.3.3. DocumentStatus : N/A *
------------| 4.2.3.3.1. MovementStatus : Texto 1 *
------------| 4.2.3.3.2. MovementStatusDate : Data e Hora *
------------| 4.2.3.3.3. Reason : Texto 50
------------| 4.2.3.3.4. SourceID : Texto 30 *
------------| 4.2.3.3.5. SourceBilling : Texto 1 *
---------| 4.2.3.4. Hash : Texto 172 *
---------| 4.2.3.5. HashControl : Texto 70 *
---------| 4.2.3.6. Period : Inteiro
---------| 4.2.3.7. MovementDate : Data *
---------| 4.2.3.8. MovementType : Texto 2 *
---------| 4.2.3.9. SystemEntryDate : Data e Hora *
---------| 4.2.3.10. TransactionID : Texto 70 **
---------| 4.2.3.11. CustomerID : Texto 30 **
---------| 4.2.3.12. SupplierID : Texto 30 **
---------| 4.2.3.13. SourceID : Texto 30 *
---------| 4.2.3.14. EACCode : Texto 5
---------| 4.2.3.15. MovementComments : Texto 60
---------| 4.2.3.16. ShipTo : N/A
------------| 4.2.3.16.1. DeliveryID : Texto 255
------------| 4.2.3.16.2. DeliveryDate : Data
------------| 4.2.3.16.3. WarehouseID : Texto 50
------------| 4.2.3.16.4. LocationID : Texto 30
------------| 4.2.3.16.5. Address : N/A
---------------| 4.2.3.16.5.1. BuildingNumber : Texto 10
---------------| 4.2.3.16.5.2. StreetName : Texto 200
---------------| 4.2.3.16.5.3. AddressDetail : Texto 210 *
---------------| 4.2.3.16.5.4. City : Texto 50 *
---------------| 4.2.3.16.5.5. PostalCode : Texto 20 *
---------------| 4.2.3.16.5.6. Region : Texto 50
---------------| 4.2.3.16.5.7. Country : Texto 2 *
---------| 4.2.3.17. ShipFrom : N/A
------------| 4.2.3.17.1. DeliveryID : Texto 255
------------| 4.2.3.17.2. DeliveryDate : Data
------------| 4.2.3.17.3. WarehouseID : Texto 50
------------| 4.2.3.17.4. LocationID : Texto 30
------------| 4.2.3.17.5. Address : N/A
---------------| 4.2.3.17.5.1. BuildingNumber : Texto 10
---------------| 4.2.3.17.5.2. StreetName : Texto 200
---------------| 4.2.3.17.5.3. AddressDetail : Texto 210 *
---------------| 4.2.3.17.5.4. City : Texto 50 *
---------------| 4.2.3.17.5.5. PostalCode : Texto 20 *
---------------| 4.2.3.17.5.6. Region : Texto 20
---------------| 4.2.3.17.5.7. Country : Texto 2 *
---------| 4.2.3.18. MovementEndTime : Data e hora
---------| 4.2.3.19. MovementStartTime : Data e hora *
---------| 4.2.3.20. ATDocCodeID : Texto 200
---------| 4.2.3.21. Line : N/A *
------------| 4.2.3.21.1. LineNumber : Inteiro *
------------| 4.2.3.21.2. OrderReferences : N/A
---------------| 4.2.3.21.2.1. OriginatingON : Texto 60
---------------| 4.2.3.21.2.2. OrderDate : Data
------------| 4.2.3.21.3. ProductCode : Texto 60 *
------------| 4.2.3.21.4. ProductDescription : Texto 200 *
------------| 4.2.3.21.5. Quantity : Decimal *
------------| 4.2.3.21.6. UnitOfMeasure : Texto 20 *
------------| 4.2.3.21.7. UnitPrice : Monetário *
------------| 4.2.3.21.8. Description : Texto 200 *
------------| 4.2.3.21.9. ProductSerialNumber : N/A
---------------| 4.2.3.21.9.1. SerialNumber : Texto 100 *
------------| 4.2.3.21.10. DebitAmount : Monetário **
------------| 4.2.3.21.11. CreditAmount : Monetário **
------------| 4.2.3.21.12. Tax : N/A **
---------------| 4.2.3.21.12.1. TaxType : Texto 3 *
---------------| 4.2.3.21.12.2. TaxCountryRegion : Texto 5 *
---------------| 4.2.3.21.12.3. TaxCode : Texto 10 *
---------------| 4.2.3.21.12.4. TaxPercentage : Decimal *
------------| 4.2.3.21.13. TaxExemptionReason : Texto 60 **
------------| 4.2.3.21.14. TaxExemptionCode : Texto 3 **
------------| 4.2.3.21.15. SettlementAmount : Monetário
------------| 4.2.3.21.16. CustomsInformation : N/A
---------------| 4.2.3.21.16.1. ARCNo : Texto 21
---------------| 4.2.3.21.16.2. IECAmount : Monetário
---------| 4.2.3.22. DocumentTotals : N/A *
------------| 4.2.3.22.1. TaxPayable : Monetário *
------------| 4.2.3.22.2. NetTotal : Monetário *
------------| 4.2.3.22.3. GrossTotal : Monetário *
------------| 4.2.3.22.4. Currency : N/A
---------------| 4.2.3.22.4.1. CurrencyCode : Texto 3 *
---------------| 4.2.3.22.4.2. CurrencyAmount : Monetário *
---------------| 4.2.3.22.4.3. ExchangeRate : Decimal *
[Embedded structures]
~> MovementOfGoods
~> StockMovement
~> DocumentStatus
~> ShipTo
~> Address
~> ShipFrom
~> Address
~> Line
~> OrderReferences
~> ProductSerialNumber
~> Tax
~> CustomsInformation
~> DocumentTotals
~> Currency
我想将其解析为嵌入了对象的 JSON,以便遵循编号创建的层次结构。
以上是从 Google Sheets 导出的一个 tsv 文件的解析版本, https ://docs.google.com/spreadsheets/d/e/2PACX-1vTFO_MoPwZmvKZOWT2J7kjGr9OC4uUb06zGxOdmXJ8h3FZ2Q0tpsoYH653Pm5mdNcM4Fs7KdlGWSkEy/pubxhtml?gid=69279
我想这样做的算法需要知道每行的“级别”是什么,当一个新的缩进即将被制作成一个新的对象时,更新的甚至嵌入其中的对象,然后回到根目录,如在
-----------
Customer
---| 2.2.1. CustomerID : Texto 30 *
---| 2.2.2. AccountID : Texto 30 *
---| 2.2.3. CustomerTaxID : Texto 30 *
---| 2.2.4. CompanyName : Texto 100 *
---| 2.2.5. Contact : Texto 50
---| 2.2.6. BillingAddress : N/A *
------| 2.2.6.1. BuildingNumber : Texto 10
------| 2.2.6.2. StreetName : Texto 200
------| 2.2.6.3. AddressDetail : Texto 210 *
------| 2.2.6.4. City : Texto 50 *
------| 2.2.6.5. PostalCode : Texto 20 *
------| 2.2.6.6. Region : Texto 50
------| 2.2.6.7. Country : Texto 12 *
---| 2.2.7. ShipToAddress : N/A
------| 2.2.7.1. BuildingNumber : Texto 10
------| 2.2.7.2. StreetName : Texto 200
------| 2.2.7.3. AddressDetail : Texto 210 *
------| 2.2.7.4. City : Texto 50 *
------| 2.2.7.5. PostalCode : Texto 20 *
------| 2.2.7.6. Region : Texto 50
------| 2.2.7.7. Country : Texto 12 *
---| 2.2.8. Telephone : Texto 20
---| 2.2.9. Fax : Texto 20
---| 2.2.10. Email : Texto 60
---| 2.2.11. Website : Texto 60
---| 2.2.12. SelfBillingIndicator : Inteiro *
[Embedded structures]
~> BillingAddress
~> ShipToAddress
例如。
我当前的代码遍历列表并检测哪些是嵌入式结构,但无法跟踪应该嵌入哪些结构,因此层次结构丢失了,或者实际上只是视觉的。在浏览每张纸之后,列出了“[嵌入式结构]”,但都是扁平的,而不是在树中。
var request = require('request')
url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vTFO_MoPwZmvKZOWT2J7kjGr9OC4uUb06zGxOdmXJ8h3FZ2Q0tpsoYH653Pm5mdNcM4Fs7KdlGWSkEy/pub?gid=692973693&single=true&output=tsv"
request(url, function (error, response, body) {
if (body != undefined) {
let lines = body.split('\r')
let lastLevel = 0
let dataStructs = [];
lines.forEach(function(line, index) {
if (index != 0) {
columns = line.split('\t')
let currentLevel = (columns[0].trim().split(".").length - 1)
if (index == 1) {
initialLevel = currentLevel;
}
if (columns[5].toLowerCase() == 'n/a') dataStructs.push(columns[2]);
if (currentLevel !== lastLevel) {
if (currentLevel > lastLevel) {
console.log(columns[0].trim(), columns[2].trim(), ':', columns[5].trim(), columns[1].trim())
} else if (currentLevel < lastLevel) {
console.log(columns[0].trim(), columns[2].trim(), ':', columns[5].trim(), columns[1].trim())
}
lastLevel = currentLevel
} else {
console.log(columns[0].trim(), columns[2].trim(), ':', columns[5].trim(), columns[1].trim())
}
}
});
console.log('\n[Embedded structures]')
dataStructs.forEach(struct => {
console.log('~>', struct/* , '=', modelName+struct, '?' */)
})
console.log('\n')
}
})
上面的代码将输出
4.2. MovementOfGoods : N/A
4.2.1. NumberOfMovementLines : Inteiro *
4.2.2. TotalQuantityIssued : Decimal *
4.2.3. StockMovement : N/A
4.2.3.1. DocumentNumber : Texto 60 *
4.2.3.2. ATCUD : Texto 100 *
4.2.3.3. DocumentStatus : N/A *
4.2.3.3.1. MovementStatus : Texto 1 *
4.2.3.3.2. MovementStatusDate : Data e Hora *
4.2.3.3.3. Reason : Texto 50
4.2.3.3.4. SourceID : Texto 30 *
4.2.3.3.5. SourceBilling : Texto 1 *
4.2.3.4. Hash : Texto 172 *
4.2.3.5. HashControl : Texto 70 *
4.2.3.6. Period : Inteiro
4.2.3.7. MovementDate : Data *
4.2.3.8. MovementType : Texto 2 *
4.2.3.9. SystemEntryDate : Data e Hora *
4.2.3.10. TransactionID : Texto 70 **
4.2.3.11. CustomerID : Texto 30 **
4.2.3.12. SupplierID : Texto 30 **
4.2.3.13. SourceID : Texto 30 *
4.2.3.14. EACCode : Texto 5
4.2.3.15. MovementComments : Texto 60
4.2.3.16. ShipTo : N/A
4.2.3.16.1. DeliveryID : Texto 255
4.2.3.16.2. DeliveryDate : Data
4.2.3.16.3. WarehouseID : Texto 50
4.2.3.16.4. LocationID : Texto 30
4.2.3.16.5. Address : N/A
4.2.3.16.5.1. BuildingNumber : Texto 10
4.2.3.16.5.2. StreetName : Texto 200
4.2.3.16.5.3. AddressDetail : Texto 210 *
4.2.3.16.5.4. City : Texto 50 *
4.2.3.16.5.5. PostalCode : Texto 20 *
4.2.3.16.5.6. Region : Texto 50
4.2.3.16.5.7. Country : Texto 2 *
4.2.3.17. ShipFrom : N/A
4.2.3.17.1. DeliveryID : Texto 255
4.2.3.17.2. DeliveryDate : Data
4.2.3.17.3. WarehouseID : Texto 50
4.2.3.17.4. LocationID : Texto 30
4.2.3.17.5. Address : N/A
4.2.3.17.5.1. BuildingNumber : Texto 10
4.2.3.17.5.2. StreetName : Texto 200
4.2.3.17.5.3. AddressDetail : Texto 210 *
4.2.3.17.5.4. City : Texto 50 *
4.2.3.17.5.5. PostalCode : Texto 20 *
4.2.3.17.5.6. Region : Texto 20
4.2.3.17.5.7. Country : Texto 2 *
4.2.3.18. MovementEndTime : Data e hora
4.2.3.19. MovementStartTime : Data e hora *
4.2.3.20. ATDocCodeID : Texto 200
4.2.3.21. Line : N/A *
4.2.3.21.1. LineNumber : Inteiro *
4.2.3.21.2. OrderReferences : N/A
4.2.3.21.2.1. OriginatingON : Texto 60
4.2.3.21.2.2. OrderDate : Data
4.2.3.21.3. ProductCode : Texto 60 *
4.2.3.21.4. ProductDescription : Texto 200 *
4.2.3.21.5. Quantity : Decimal *
4.2.3.21.6. UnitOfMeasure : Texto 20 *
4.2.3.21.7. UnitPrice : Monetário *
4.2.3.21.8. Description : Texto 200 *
4.2.3.21.9. ProductSerialNumber : N/A
4.2.3.21.9.1. SerialNumber : Texto 100 *
4.2.3.21.10. DebitAmount : Monetário **
4.2.3.21.11. CreditAmount : Monetário **
4.2.3.21.12. Tax : N/A **
4.2.3.21.12.1. TaxType : Texto 3 *
4.2.3.21.12.2. TaxCountryRegion : Texto 5 *
4.2.3.21.12.3. TaxCode : Texto 10 *
4.2.3.21.12.4. TaxPercentage : Decimal *
4.2.3.21.13. TaxExemptionReason : Texto 60 **
4.2.3.21.14. TaxExemptionCode : Texto 3 **
4.2.3.21.15. SettlementAmount : Monetário
4.2.3.21.16. CustomsInformation : N/A
4.2.3.21.16.1. ARCNo : Texto 21
4.2.3.21.16.2. IECAmount : Monetário
4.2.3.22. DocumentTotals : N/A *
4.2.3.22.1. TaxPayable : Monetário *
4.2.3.22.2. NetTotal : Monetário *
4.2.3.22.3. GrossTotal : Monetário *
4.2.3.22.4. Currency : N/A
4.2.3.22.4.1. CurrencyCode : Texto 3 *
4.2.3.22.4.2. CurrencyAmount : Monetário *
4.2.3.22.4.3. ExchangeRate : Decimal *
[Embedded structures]
~> MovementOfGoods
~> StockMovement
~> DocumentStatus
~> ShipTo
~> Address
~> ShipFrom
~> Address
~> Line
~> OrderReferences
~> ProductSerialNumber
~> Tax
~> CustomsInformation
~> DocumentTotals
~> Currency
如何以树状形式查看这些列表并将字段/属性添加到正确的嵌入对象或对象的根?
编辑:
以上面的“客户”为例,使用表格结构,例如https://docs.google.com/spreadsheets/d/e/2PACX-1vTFO_MoPwZmvKZOWT2J7kjGr9OC4uUb06zGxOdmXJ8h3FZ2Q0tpsoYH653Pm5mdNcM4Fs7KdlGWSkEy/pubhtml?gid=700343
{
"Customer": {
"2.2.1. CustomerID": "Texto 30 *",
"2.2.2. AccountID": "Texto 30 *",
"2.2.3. CustomerTaxID": "Texto 30 *",
"2.2.4. CompanyName": "Texto 100 *",
"2.2.5. Contact": "Texto 50",
"2.2.6. BillingAddress": {
"2.2.6.1. BuildingNumber": "Texto 10",
"2.2.6.2. StreetName": "Texto 200",
"2.2.6.3. AddressDetail": "Texto 210 *",
"2.2.6.4. City": "Texto 50 *",
"2.2.6.5. PostalCode": "Texto 20 *",
"2.2.6.6. Region": "Texto 50 ",
"2.2.6.7. Country": "Texto 12 *"
},
"2.2.7. ShipToAddress": {
"2.2.7.1. BuildingNumber": "Texto 10",
"2.2.7.2. StreetName": "Texto 200",
"2.2.7.3. AddressDetail": "Texto 210 *",
"2.2.7.4. City": "Texto 50 *",
"2.2.7.5. PostalCode": "Texto 20 *",
"2.2.7.6. Region": "Texto 50",
"2.2.7.7. Country": "Texto 12 *"
},
"2.2.8. Telephone ": "Texto 20",
"2.2.9. Fax": "Texto 20",
"2.2.10. Email": "Texto 60",
"2.2.11. Website": "Texto 60",
"2.2.12. SelfBillingIndicator": "Inteiro *"
}
}
编辑2:要清楚,所需的“结果”是能够检测嵌套对象何时开始和结束,以及根据源表将它们嵌套在正确的位置。表中传递给 JSON 的特定列可能会有所不同,并且实际使用的语法也会从 JSON 更改为例如 rails 生成器。我缺少的是代码的“级别检测”部分。
编辑3:
var request = require('request')
url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vTFO_MoPwZmvKZOWT2J7kjGr9OC4uUb06zGxOdmXJ8h3FZ2Q0tpsoYH653Pm5mdNcM4Fs7KdlGWSkEy/pub?gid=700343422&single=true&output=tsv"
request(url, function (error, response, body) {
if (body != undefined) {
let lines = body.split('\r')
let lastLevel = 0
let dataStructs = [];
goneUpCounter = 0;
console.log("{")
lines.forEach(function (line, index) {
if (index != 0) {
columns = line.split('\t')
let currentLevel = (columns[0].trim().split(".").length - 1)
if (columns[5].toLowerCase() == 'n/a') {
dataStructs.push(columns[2]);
goneUpCounter += 1;
}
if (currentLevel !== lastLevel) {
if (currentLevel > lastLevel) {
if (columns[5].toLowerCase() == 'n/a') {
console.log("{\"" + columns[2].trim() + "\" : {")
} else {
console.log("\"" + columns[0].trim(), columns[2].trim() + "\"", ':', "\"" + columns[5].trim(), columns[1].trim() + "\",")
}
} else if (currentLevel < lastLevel) {
if (columns[5].toLowerCase() == 'n/a') {
console.log("\"" + columns[2].trim() + "\" : {")
} else {
console.log("\"" + columns[0].trim(), columns[2].trim() + "\"", ':', "\"" + columns[5].trim(), columns[1].trim() + "\",")
}
}
lastLevel = currentLevel
} else {
if (columns[5].toLowerCase() == 'n/a') {
console.log("\"" + columns[2].trim() + "\" : {")
} else {
if ((lines[index + 1] != undefined && lines[index + 1].split('\t')[0].trim().split('.').length - 1 < lastLevel) || index + 1 == lines.length) {
console.log("\"" + columns[0].trim(), columns[2].trim() + "\"", ':', "\"" + columns[5].trim(), columns[1].trim() + "\"")
} else {
console.log("\"" + columns[0].trim(), columns[2].trim() + "\"", ':', "\"" + columns[5].trim(), columns[1].trim() + "\",")
}
}
if (lines[index + 1] != undefined && lines[index + 1].split('\t')[0].trim().split('.').length - 1 < lastLevel) {
goneUpCounter -= 1;
console.log('},')
}
}
}
});
for (let i = 0; i < goneUpCounter + 1; i++) {
console.log('}')
}
}
})
返回有效的 JSON,但代码很糟糕。
{
"2.2.1. CustomerID": "Texto 30 *",
"2.2.2. AccountID": "Texto 30 *",
"2.2.3. CustomerTaxID": "Texto 30 *",
"2.2.4. CompanyName": "Texto 100 *",
"2.2.5. Contact": "Texto 50 ",
"BillingAddress": {
"2.2.6.1. BuildingNumber": "Texto 10 ",
"2.2.6.2. StreetName": "Texto 200 ",
"2.2.6.3. AddressDetail": "Texto 210 *",
"2.2.6.4. City": "Texto 50 *",
"2.2.6.5. PostalCode": "Texto 20 *",
"2.2.6.6. Region": "Texto 50 ",
"2.2.6.7. Country": "Texto 12 *"
},
"ShipToAddress": {
"2.2.7.1. BuildingNumber": "Texto 10 ",
"2.2.7.2. StreetName": "Texto 200 ",
"2.2.7.3. AddressDetail": "Texto 210 *",
"2.2.7.4. City": "Texto 50 *",
"2.2.7.5. PostalCode": "Texto 20 *",
"2.2.7.6. Region": "Texto 50 ",
"2.2.7.7. Country": "Texto 12 *"
},
"2.2.8. Telephone": "Texto 20 ",
"2.2.9. Fax": "Texto 20 ",
"2.2.10. Email": "Texto 60 ",
"2.2.11. Website": "Texto 60 ",
"2.2.12. SelfBillingIndicator": "Inteiro *"
}