Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
大數據項目開發過程中,ETL(Extract-Transform-Load)必不可少。即使目前 JSON 非常流行,開發人員也必定有機會面對遠古系統的挑戰,而 XML 格式的數據源作為經典存在渾身上下散發著濃濃 old money 的味道。
因為有 Newtonsoft.Json 這樣優秀的 JSON 框架存在,開發人員可以很容易的對 JSON 格式的字符串反序列化。但是 XML 格式的數據就沒有這么方便了:雖然 .NET 中內置了對 XML 序列化和反序列化的支持,但遇到需要對接外部數據時就不是很方便了。
從 XML 中提取目標數據最高效,也最麻煩的方式是直接使用 XmlReader :
<employee xmlns="urn:empl-hire">
<ID>12365</ID>
<hire-date>2003-01-08</hire-date>
<title>Accountant</title>
</employee>
使用以下代碼對上述 hireDate.xml 文件讀取:
using (XmlReader reader = XmlReader.Create("hireDate.xml")) {
// Move to the hire-date element.
reader.MoveToContent();
reader.ReadToDescendant("hire-date");
// Return the hire-date as a DateTime object.
DateTime hireDate = reader.ReadElementContentAsDateTime();
Console.WriteLine("Six Month Review Date: {0}", hireDate.AddMonths(6));
}
輸出:
Six Month Review Date: 7/8/2003 12:00:00 AM
在 .NET Framework 3.5 發布后的時間里,開發人員可以使用 XDocument 來生成和解析 XML 文檔,這要比 XmlReader 方便得多:
string str =
@"<?xml version=""1.0""?>
<!-- comment at the root level -->
<Root>
<Child>Content</Child>
</Root>";
XDocument doc = XDocument.Parse(str);
Console.WriteLine(doc.XPathSelectElement("//Child"));
輸出:
<Child>Content</Child>
但硬編碼的 XPath 并不方便調試,而且需要時刻關注空引用的問題。在 XML 格式復雜、項目工程比較大時使用起來也不方便。
在計算機科學中,可擴展樣式表轉換語言(英語:Extensible Stylesheet Language Transformations,縮寫XSLT)是一種樣式轉換標記語言,可以將XML數據檔轉換為另外的XML或其它格式,如HTML網頁,純文字。XSLT最末的T字母表示英語中的“轉換”(transformation)。
簡單來說,開發人員可以借助 XSLT 技術編寫一個 XML 文件,并使用該文件將一種 XML 格式轉換為另一種 XML 。即:在對接復雜格式 XML 數據源時,開發人員可以編寫一個后綴為 .xsl 的文件,并使用該文件將數據源格式轉換為自己需要的格式(比如可以適配 XML 反序列化的格式)。
從一個簡單的 XML 文件開始:
<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
.
.
.
</catalog>
如果直接在瀏覽器打開這個文件:
假設我們只關心所有的 title 信息,可以使用下面的 cdcatalog.xsl 文件,該文件可以將 cdcatalog.xml 轉為 XmlSerializer 所需要的格式:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:for-each select="catalog/cd">
<string>
<xsl:value-of select="title"/>
</string>
</xsl:for-each>
</ArrayOfString>
</xsl:template>
</xsl:stylesheet>
為了可以在瀏覽器中直接觀察到轉換效果,可以選擇把 XSL 樣式表鏈接到 XML 文檔:向 XML 文檔(”cdcatalog.xml”)添加 XSL 樣式表引用即可。
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="cdcatalog.xsl"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
.
.
.
</catalog>
刷新瀏覽器,打開開發者工具:
也可以在: https://www.coderbusy.com/demos/2021/1531/cdcatalog.xml 查看在線示例。
從上面的操作可以看出,調試 XLS 文件的成本是很低的,開發者可以很容易對 XLS 文件進行更改,并在短時間之內得到運行結果。
在 C# 中,可以使用 XslCompiledTransform 進行 XSL 轉換。以下代碼展示這個轉換過程:
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load("cdcatalog.xsl");
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
using (var xw = new XmlTextWriter(sw) { Formatting = Formatting.Indented })
{
xsl.Transform("cdcatalog.xml", xw);
}
}
var xml = sb.ToString();
Console.WriteLine(xml);
以上代碼會產生如下輸出:
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>Empire Burlesque</string>
<string>Hide your heart</string>
<string>Greatest Hits</string>
<string>Still got the blues</string>
<string>Eros</string>
.
.
.
</ArrayOfString>
轉換 XML 不是目的,能直接拿到數據對象才是。以上的代碼完成了格式轉換,接著需要對轉換好的 XML 字符串反序列化:
var xmlSerializer = new XmlSerializer(typeof(List<string>));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
var list = (List<string>) xmlSerializer.Deserialize(ms);
foreach (var item in list)
{
Console.WriteLine(item);
}
}
以上代碼借助 XmlSerializer 實現了反序列化功能,這會產生以下輸出:
Empire Burlesque
Hide your heart
Greatest Hits
Still got the blues
Eros
...
本文所述的轉換和反序列化技術已經在真實的生產環境中得到驗證,千萬級的數據處理也毫不費力。
本文包含的演示的代碼和數據可以在 Gitee 上找到:
https://gitee.com/coderbusy/demo/tree/master/hello-xslt/HelloXslt
者:前端小智 來源:大遷世界
.md文件是markdown的一種標記語言,和html比較起來,更簡單快捷,主要體現在:標記符的數量和書寫上。
方式一:使用i5ting_toc插件
需要先安裝npm(安裝node.js后會自帶npm),然后才能安裝i5ting插件:
npm install i5ting_toc -g
執行命令行生成html文件,在輸入前要進入到對應根目錄下:
i5ting_toc -f **.md
需要注意的是:寫md文檔的特殊符號時記得添加空格。小技巧:如何快速在當前目錄打開cmd?選擇當前目錄,按住shift,然后鼠標右鍵在此處打開命令窗口(在此處打開powerShell窗口)。
方式二:使用gitbook
同樣先需要安裝node,然后運行:
npm i gitbook gitbook-cli -g
生成md文件,這個命令會生成相應的md的文件,然后在相應的文件里寫你的內容即可:
gitbook init
md轉html,生成一個_doc目錄,打開就可以看到你html文件了。
gitbook build
方式三:利用前端代碼
實現原理是采用node.js搭建服務器,讀取md文件轉化為html片斷。瀏覽器發送ajax請求獲取片段后再渲染生成html網頁。
node代碼:
var express = require('express');
var http = require('http');
var fs = require('fs');
var bodyParser = require('body-parser');
var marked = require('marked'); // 將md轉化為html的js包
var app = express();
app.use(express.static('src')); //加載靜態文件
var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.get('/getMdFile',urlencodedParser, function(req, res) {
var data = fs.readFileSync('src/test.md', 'utf-8'); //讀取本地的md文件
res.end(JSON.stringify({
body : marked(data)
}));
} );
//啟動端口監聽
var server = app.listen(8088, function () {
var host = server.address().address;
var port = server.address().port;
console.log("應用實例,訪問地址為 http://%s:%s", host, port)
});
前端html:
<div id="content"> <h1 class="title">md-to-HTML web app</h1> <div id="article"> </div></div><script type="text/JavaScript" src="js/jquery-1.11.3.min.js"></script><script> var article = document.getElementById('article'); $.ajax({ url: "/getMdFile", success: function(result) { console.log('數據獲取成功'); article.innerHTML = JSON.parse(result).body; }, error: function (err) { console.log(err); article.innerHTML = '<p>獲取數據失敗</p>'; } });</script>
面是我們如何在 JavaScript 中輕松地將 JSON 轉換為 CSV:
function jsonToCsv(items) {
const header = Object.keys(items[0]); const headerString = header.join(','); // handle null or undefined values here
const replacer = (key, value) => value ?? ''; const rowItems = items.map((row) =>
header
.map((fieldName) => JSON.stringify(row[fieldName], replacer))
.join(',')
); // join header and body, and break into separate lines
const csv = [headerString, ...rowItems].join('\r\n'); return csv;
}const obj = [
{ color: 'red', maxSpeed: 120, age: 2 },
{ color: 'blue', maxSpeed: 100, age: 3 },
{ color: 'green', maxSpeed: 130, age: 2 },
];const csv = jsonToCsv(obj);console.log(csv);
這將是 CSV 輸出:
color,maxSpeed,age
"red",120,2
"blue",100,3
"green",130,2
了解步驟
我們創建了一個可重用的 jsonToCsv() 函數來讓我們將多個 JSON 字符串轉換為 CSV。 它需要一個包含對象的數組。 每個對象將在 CSV 輸出中占據一行。
我們在此函數中所做的第一件事是獲取將用于 CSV 標頭的所有鍵。 我們希望數組中的所有對象都具有相同的鍵,因此我們使用 Object.keys() 方法將鍵從第一個對象項中提取到數組中。
const obj = [
{ color: 'red', maxSpeed: 120, age: 2 },
{ color: 'blue', maxSpeed: 100, age: 3 },
{ color: 'green', maxSpeed: 130, age: 2 },
];// { color: 'red', maxSpeed: 120, age: 2 }
console.log(obj[0]);// [ 'color', 'maxSpeed', 'age' ]
console.log(Object.keys(obj[0]));
獲取鍵后,我們調用數組的 join() 方法將所有元素連接成 CSV 標頭字符串。
const header = ['color', 'maxSpeed', 'age'];const headerString = arr.join(',');console.log(headerString); // color,maxSpeed,age
接下來,我們創建一個函數,該函數將作為回調傳遞給 JSON.stringify() 函數的 replacer 參數。 此函數將處理 JSON 數組中對象的未定義或空屬性值。
const obj = { prop1: 'Earth', prop2: undefined };// replace undefined property values with empty string ('')
const replacer = (key, value) => value ?? '';const str = JSON.stringify(obj, replacer);// {"prop1":"Earth","prop2":""}
console.log(str);
然后我們使用 Array map() 方法從每個對象中獲取屬性值。 map() 接受一個回調函數,該函數在每個數組元素上調用以返回一個轉換。
此回調使用標頭數組來獲取每個對象的所有鍵。 再次調用 map(),它會遍歷每個鍵,獲取對象中該鍵的對應值,并使用 JSON.stringify() 將其轉換為字符串。
這個對 map() 的內部調用最終會產生一個數組,該數組包含數組中當前對象的所有字符串化屬性值。
const header = ['color', 'maxSpeed', 'age'];const row = { color: 'red', maxSpeed: 120, age: 2 };const replacer = (key, value) => value ?? '';const rowItem = header.map((fieldName) =>
JSON.stringify(row[fieldName], replacer)
);// array of stringified property values
console.log(rowItem); // [ '"red"', '120', '2' ]
將對象轉換為屬性值數組后,使用 join() 將數組轉換為 CSV 行。
['"red"', '120', '2'].join(',') // -> "red",120,2
因此,這種轉換發生在 JSON 數組中的每個對象上,以生成 CSV 行列表,存儲在我們原始示例中的 rowItems 變量中。
為了生成最終的 CSV 輸出,我們使用擴展語法 (...) 將 headerString 和 rowItems 組合到一個數組中。
const headerString = ['color', 'maxSpeed', 'age'];const rowItems = ['"red",120,2', '"blue",100,3', '"green",130,2'];[headerString, ...rowItems];
/*
Output ->
[
[ 'color', 'maxSpeed', 'age' ],
'"red",120,2',
'"blue",100,3',
'"green",130,2'
]
*/
然后我們在這個數組上調用 join() 并使用 '\r\n' 字符串作為分隔符,以創建一個帶有 CSV 標題的字符串,并且每個 CSV 行位于單獨的行中。
const headerString = ['color', 'maxSpeed', 'age'];const rowItems = ['"red",120,2', '"blue",100,3', '"green",130,2'];console.log([headerString, ...rowItems].join('\r\n'));
/*
color,maxSpeed,age
"red",120,2
"blue",100,3
"green",130,2
*/
關注七爪網,獲取更多APP/小程序/網站源碼資源!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。