整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          都2021年竟然有人搞大數據忽略JSON去研究C#把XML轉換為XML的技術

          大數據項目開發過程中,ETL(Extract-Transform-Load)必不可少。即使目前 JSON 非常流行,開發人員也必定有機會面對遠古系統的挑戰,而 XML 格式的數據源作為經典存在渾身上下散發著濃濃 old money 的味道。

          因為有 Newtonsoft.Json 這樣優秀的 JSON 框架存在,開發人員可以很容易的對 JSON 格式的字符串反序列化。但是 XML 格式的數據就沒有這么方便了:雖然 .NET 中內置了對 XML 序列化和反序列化的支持,但遇到需要對接外部數據時就不是很方便了。

          使用 XmlReader 讀取數據

          從 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

          使用 XDocument 讀取數據

          在 .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 格式復雜、項目工程比較大時使用起來也不方便。

          一種把 XML 轉換為 XML 的技術: XSLT

          在計算機科學中,可擴展樣式表轉換語言(英語: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# 中使用 XSLT 技術

          在 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 不是目的,能直接拿到數據對象才是。以上的代碼完成了格式轉換,接著需要對轉換好的 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

          一篇文章我們介紹了一個html/xml解析器——htmlparser,這篇文章我們介紹另外一個解析模塊htmlparser2,后者是對前者的重構,同時對前者的API做了部分兼容。

          用法簡介

          安裝

          const { Parser } = require('htmlparser2');
          const parser = new Parser(handler, options);
          parser.parseComplete('html/xml內容');

          寫法

          const { Parser } = require('htmlparser2');
          const parser = new Parser(handler, options);
          parser.parseComplete('html/xml內容');

          htmlparser2提供了一個解析器——Parser,初始化它至少需要一個handler,options是可選的。

          handler是一個對象,在這個對象上可以設置很多的鉤子函數,Parser解析時會在每個階段運行對應的鉤子函數。

          以下是可以設置的所有的鉤子函數,

        1. onopentag(<str> name, <obj> attributes)
        2. onopentagname(<str> name)
        3. onattribute(<str> name, <str> value)
        4. ontext(<str> text)
        5. onclosetag(<str> name)
        6. onprocessinginstruction(<str> name, <str> data)
        7. oncomment(<str> data)
        8. oncommentend()
        9. oncdatastart()
        10. oncdataend()
        11. onerror(<err> error)
        12. onreset()
        13. onend()
        14. htmlparser模塊是通過正則表達式來解析html內容的,而htmlparser2則不同,它會按順序讀取html的每個字符,并且推測后面字符是標簽名、屬性還是其他的類型,所以htmlparser2在解析完每一個標簽后都會運行相應的鉤子函數。

          先來看一下例子,

          圖1

          圖1中設置了所有的鉤子函數以便來說明每個鉤子函數的作用,運行一下,

          圖2

          對照圖1和圖2就能看出來每個鉤子函數的運行時機,這其中有以下幾個鉤子函數需要注意一下。

          • oncdatastart和oncdataend會在解析<![CDATA[文本]]>標簽時觸發,但是觸發的前提是選項設置了recognizeCDATA=true或者xmlMode=true;
          • onprocessinginstruction會在解析<!xxyy>或者<?xxyy>這樣的標簽時觸發,xx和yy中間可以有分隔符(斜杠或者空格),分隔符前面的字符串就是鉤子函數中的name的值;
          • 運行parseComplete方法會執行reset鉤子函數,如果僅僅執行parser的write或者end方法并不會執行reset方法。

          除了自定義handler以外,htmlparser2還提供了幾個handler,比如DomHandler,用法如下:

          圖3

          運行一下,我們看看結果,

          圖4

          如果4所示,DomHandler處理的結果是以數組的形式輸出的,在每個單元數據中還可以拿到上一個、下一個以及父節點的數據。

          htmlparser2還可以通過操作流Stream解析內容,寫法如下:

          圖5

          總結

          這篇文章和上一篇是姊妹篇,都是介紹解析html/xml內容的模塊,通過對比,我們發現htmlparser2模塊功能更強大一些,也更靈活一些,同時也兼容htmlparser模塊的一些接口。雖然兩者功能類似,但是這給了我們更多的選擇性。

          喜歡我的文章就關注我吧,有問題可以發表評論,我們一起學習,共同成長!

          面是我們如何在 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/小程序/網站源碼資源!


          主站蜘蛛池模板: 中文字幕亚洲一区| 无码视频免费一区二三区| 色视频综合无码一区二区三区 | 学生妹亚洲一区二区| 好吊妞视频一区二区| 国产精品一区二区久久| 国产成人一区二区在线不卡| 中文字幕一区在线观看视频| 亚洲一区二区精品视频| 国精产品一区一区三区| 乱精品一区字幕二区| 成人在线视频一区| 日本精品一区二区三区视频| 玩弄放荡人妻一区二区三区| 欧美日韩精品一区二区在线观看| 精品无码综合一区二区三区| 日韩精品一区二区三区中文3d | 在线视频一区二区三区三区不卡 | 国产精品特级毛片一区二区三区| 久久久精品人妻一区二区三区蜜桃 | 亚洲欧美一区二区三区日产| 亚洲一区AV无码少妇电影| 精品国产一区二区三区www| V一区无码内射国产| 亚洲爆乳精品无码一区二区三区| 色久综合网精品一区二区| 人妻夜夜爽天天爽一区| 国产午夜精品一区二区三区漫画| 精品视频一区二区三三区四区| 国产成人一区二区三区免费视频 | 日本v片免费一区二区三区| 熟妇人妻系列av无码一区二区| 国产微拍精品一区二区| 无码av免费一区二区三区试看| 视频一区二区三区人妻系列| 亚洲一区二区影视| 精品久久一区二区| 亚洲欧洲精品一区二区三区| 99久久精品午夜一区二区| 久久精品亚洲一区二区| 亚洲乱码一区二区三区在线观看 |