鍵.png)
node.js + express + docker + mysql + jwt 實(shí)現(xiàn)用戶管理restful api
<vehicles xmlns="http://example.com/vehicles">
<item>
<name>Cars</name>
<description>I love cars.</description>
<models>
<model>Range Rover</model>
<model>Corolla</model>
<model>BMW</model>
<model>Toyota</model>
<model>Tesla</model>
</models>
</item>
</vehicles>
這些元素按層次結(jié)構(gòu)進(jìn)行組織,使文檔易于人類和計(jì)算機(jī)理解。
您可以使用如 JSONformatter(等工具來查看 XML 元素的樹狀結(jié)構(gòu)。這一方法既適用于我們的示例,也適用于您所擁有的任何 XML 數(shù)據(jù)。以這種方式查看 XML 有助于您掌握元素的組織方式。
現(xiàn)在我們已經(jīng)介紹了有關(guān) XML 文件組件的基本信息,我們可以使用此信息來幫助解析具有各種庫的 XML 文件。
XML 解析是分析 XML 文檔并提取所需數(shù)據(jù)的過程。
通常,XML 解析器執(zhí)行以下關(guān)鍵步驟:
創(chuàng)建自定義 XML 解析通常具有挑戰(zhàn)性,尤其是在實(shí)現(xiàn)自定義解決方案時(shí)。
XML 文件執(zhí)行更嚴(yán)格的規(guī)則;例如,缺少?zèng)]有引號的標(biāo)簽或?qū)傩钥赡軙?huì)導(dǎo)致文件不可用。另外,由于XML文檔具有自描述性質(zhì),因此很難將其拆分成能夠并行解析的塊。
除非您有充分的理由,否則,使用標(biāo)準(zhǔn)且經(jīng)過充分測試的解析器庫和API,以避免解析過程的復(fù)雜性,會(huì)是一個(gè)更為有效的選擇。
與其他語言一樣,JavaScript 提供了多個(gè)可用于解析 XML 文件的 API 和庫。他們每個(gè)人都有其獨(dú)特的權(quán)衡。
有些針對速度進(jìn)行了優(yōu)化,有些針對內(nèi)存進(jìn)行了優(yōu)化;無論您選擇使用哪種方式,在很大程度上取決于您的項(xiàng)目要求。
在本指南中,我們將介紹以下內(nèi)容:
文檔對象模型 (DOM) 將文檔的結(jié)構(gòu)表示為節(jié)點(diǎn)樹,其中每個(gè)節(jié)點(diǎn)對應(yīng)于標(biāo)記中的元素、屬性或值。
此樹結(jié)構(gòu)允許解析器以編程方式訪問、操作和修改 XML 內(nèi)容。
JavaScript 提供了DOMParser API,它提供了一種方法,可以將XML內(nèi)容解析成XML文檔,這些文檔能夠輕松地遍歷和訪問,以便進(jìn)行后續(xù)的處理。
現(xiàn)在,讓我們看看如何使用此 API 解析 XML。首先,創(chuàng)建一個(gè)本地開發(fā)環(huán)境,我們將使用它來處理代碼示例,同時(shí)按照本指南進(jìn)行操作。
為此,請?jiān)诮K端中運(yùn)行以下命令以創(chuàng)建一個(gè)演示項(xiàng)目目錄和兩個(gè)文件:.index.
和一個(gè) jstest.xml
mkdir parsing-xml
cd parsing-xml
# For Linux/Unix systems:
touch index.js test.xml
# For Windows:
_echo. > index.js_
echo. > test.xml
然后,在 XML 示例中的test.xml
粘貼中,我們查看了如下:
<?xml version="1.0" encoding="UTF-8"?>
<vehicles xmlns="http://example.com/vehicles">
<item>
<name>Cars</name>
<description>I love cars.</description>
<models>
<model>Range Rover</model>
<model>Corolla</model>
<model>BMW</model>
<model>Toyota</model>
<model>Tesla</model>
</models>
</item>
</vehicles>
要使用 DOMParser API 解析 XML 數(shù)據(jù),需要注意幾個(gè)要點(diǎn)。
DOMParser API 是現(xiàn)代瀏覽器中支持的本機(jī) Web API。即便如此,在處理 XML 文件時(shí),也不能使用 DOMParser API 實(shí)例方法直接解析它們,即 parseFromString()
— 該方法需要 XML 字符串作為輸入,而不是文件路徑或 URL。
換句話說,它不具備從文件系統(tǒng)中讀取文件或向服務(wù)器發(fā)送請求以獲取XML文件的功能。相反,它的設(shè)計(jì)初衷是處理那些在內(nèi)存中已經(jīng)可用的XML源代碼字符串。
由于預(yù)期是您將處理需要在任何其他處理之前進(jìn)行解析的大型 XML 文件,因此正確加載這些文件非常重要。為此,您需要:
parseFromString()
字符串傳遞給 DOMParser API 實(shí)例方法進(jìn)行解析。完成這些步驟后,您可以使用 DOM 方法訪問解析的 XML。
讓我們看一個(gè)代碼可能是什么樣子的示例。在index.js
文件中,粘貼以下代碼:
async function loadXML() {
try {
const response = await fetch('test.xml');
const xmlString = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, 'text/xml');
const name = xmlDoc.querySelector('name').textContent;
console.log(name);
} catch (error) {
console.error('Error loading XML:', error);
}
}
loadXML()
現(xiàn)在,在同一個(gè)項(xiàng)目目錄中,創(chuàng)建一個(gè)文件并添加以下代碼:
<!DOCTYPE html>
<html>
<head>
<title>XML Parser</title>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
此時(shí),要顯示解析后的名稱,請?jiān)跒g覽器中打開index.html
文件,導(dǎo)航到開發(fā)人員工具中的瀏覽器控制臺,并希望能查看輸出。
這種方法在技術(shù)上是正確的。但是,由于我們使用 Fetch API 在您的本地環(huán)境中加載 XML 文件,因此它不會(huì)工作,并且瀏覽器很可能會(huì)引發(fā)錯(cuò)誤。這是因?yàn)?Web 服務(wù)器尚未提供文件。
現(xiàn)代瀏覽器使用同源安全策略。這個(gè)策略會(huì)阻止網(wǎng)頁向不同于為該頁面提供服務(wù)的域的其它域發(fā)起請求。在使用 Fetch API 本地加載 XML 文件時(shí),我們就會(huì)遇到這樣的策略限制。這是一項(xiàng)安全措施,但它可能會(huì)阻礙當(dāng)?shù)匕l(fā)展。
當(dāng)您直接從文件系統(tǒng)打開 HTML 文件時(shí),瀏覽器會(huì)將其視為具有唯一的來源。使用 JavaScript 的 Fetch API 獲取本地文件(包括 XML 文件)的任何嘗試都將被同源策略阻止。瀏覽器可能會(huì)因?yàn)榭缬蛘埱螅–ORS)策略而引發(fā)阻止錯(cuò)誤,或者出現(xiàn)其他與安全相關(guān)的類似錯(cuò)誤。
為了克服這個(gè)限制,我們需要從 Web 服務(wù)器提供我們的文件。這種方法確保我們的所有文件(HTML、JavaScript 和 XML)都從同一源提供,從而滿足同源策略要求。
有幾種方法可以實(shí)現(xiàn)此目的:
在本演示中,我們將在 Visual Studio Code 中使用 Live Server 擴(kuò)展。這個(gè)擴(kuò)展提供了一個(gè)快速且簡便的方法,使我們能夠在本地提供文件,而無需進(jìn)行復(fù)雜的服務(wù)器設(shè)置。
要使用 Live Server:
在本地服務(wù)器運(yùn)行后,您的瀏覽器現(xiàn)在可以獲取 XML 文件。
要打開瀏覽器的控制臺,您需要訪問瀏覽器的開發(fā)人員工具。為此,請右鍵單擊,選擇 檢查,然后單擊 控制臺 選項(xiàng)卡。
在這里,您應(yīng)該看到 XML 解析腳本的輸出。
這種設(shè)置允許我們在瀏覽器中使用 DOMParser API 直接解析 XML 文件。此基本步驟為更復(fù)雜的 XML 處理任務(wù)奠定了基礎(chǔ)。
上面的示例主要聚焦于在瀏覽器環(huán)境中解析XML內(nèi)容。但值得注意的是,相同的過程在服務(wù)器端環(huán)境中同樣適用——您依然可以使用相同的DOMParser API方法來解析XML數(shù)據(jù)。
這可以使用像 XMLDOM 這樣的包來實(shí)現(xiàn) — 它提供了一個(gè) DOMParser 實(shí)現(xiàn),允許您在 Node.js 服務(wù)器環(huán)境中解析 XML。
要使用 ,我們首先需要設(shè)置一個(gè)本地服務(wù)器端開發(fā)環(huán)境。為此,您需要首先安裝 Node.js 和 Node 包管理器 npm。
首先,為此示例創(chuàng)建一個(gè)新的項(xiàng)目目錄,或者您可以使用當(dāng)前的工作目錄。然后,通過在終端中運(yùn)行以下命令來初始化新的 Node.js 項(xiàng)目:
npm init --y
接下來,安裝 .xmldom
npm install @xmldom/xmldom
現(xiàn)在,在項(xiàng)目文件夾的根目錄中,創(chuàng)建一個(gè)新文件。
# For Linux/Unix systems:
touch app.js
# For Windows:
_echo. > app.js_
然后,粘貼以下代碼:
import fs from 'fs';
import { DOMParser } from '@xmldom/xmldom';
const xml = fs.readFileSync('test.xml', 'utf8');
const parser = new DOMParser();
const doc = parser.parseFromString(xml, 'application/xml');
console.log(doc.getElementsByTagName('name')[0].textContent);
在此示例中,我們執(zhí)行兩個(gè)主要操作:
fs
模塊將整個(gè) XML 文件 (test.xml
) 作為字符串同步讀入內(nèi)存。DOMParser
的實(shí)例并使用parseFromString
方法解析 XML 數(shù)據(jù)。解析后,我們可以使用 DOM 遍歷方法訪問單個(gè)元素。在這種情況下,我們使用 getElementsByTagName
和 textContent
檢索第一個(gè)元素的文本內(nèi)容。
確保通過添加屬性來更新文件,以便在文件中使用 ES6 語法。
您可以在終端上運(yùn)行此命令來測試此最小設(shè)置。
node app.js
輸出將是 XML 文件中第一個(gè)元素的文本內(nèi)容,即:.Cars
xml2js 庫是用于解析 XML 數(shù)據(jù)的常用 Node.js 包。與DOMParser(它提供XML的DOM表示)不同,這個(gè)方法更側(cè)重于將XML轉(zhuǎn)換為一種更便于在JavaScript應(yīng)用程序中使用的格式。
對于您希望快速訪問API或其他服務(wù)中的數(shù)據(jù),而又不想處理通過操作DOM來訪問所需數(shù)據(jù)的復(fù)雜性的場景,它特別有用。
實(shí)質(zhì)上,xml2js
允許您將 XML 直接解析為 JSON 格式。由于 JSON 是應(yīng)用程序中使用的一種常見格式,因此您的使用者(API、客戶端等)可以輕松攝取和使用解析后的數(shù)據(jù)。
要使用 ,首先,安裝軟件包:xml2js
npm install xml2js
安裝后,要解析 XML 文件,請首先使用fs
模塊讀取文件,然后使用xml2js
將 XML 字符串轉(zhuǎn)換為 JavaScript 對象。
下面是如何執(zhí)行此操作的示例:
import fs from 'fs';
import { parseString } from 'xml2js';
const xml = fs.readFileSync('test.xml', 'utf8');
parseString(xml, (err, result) => {
if (err) {
console.error('Error parsing XML:', err);
return;
}
console.log(result);
});
在此代碼片段中,我們讀取 test.xml
字符串的內(nèi)容,然后使用該parseString
函數(shù)將 XML 字符串轉(zhuǎn)換為 JavaScript 對象(JSON 對象)。
當(dāng)您運(yùn)行此代碼時(shí),您將獲得如下輸出:
{
vehicles: { '$': { xmlns: '[http://example.com/vehicles](http://example.com/vehicles)' }, item: [ [Object] ] }
}
這并不完全是錯(cuò)誤,您不用擔(dān)心!這種輸出的原因是parseString
方法遵循了Node.js的默認(rèn)行為,即在記錄大型或嵌套的對象時(shí),通常會(huì)限制檢查的深度,因此導(dǎo)致了這樣的輸出(這一行為在GitHub存儲庫中有明確的說明)。
要查看已解析的 XML 的完整結(jié)構(gòu),可以使用util.inspect
方法?,F(xiàn)在,您可以獲得 JSON 對象的更詳細(xì)結(jié)構(gòu)。
繼續(xù)導(dǎo)入util
模塊,將result
對象包裝在util.inspect
方法中,然后將其記錄在終端中。
import util from 'util';
console.log(util.inspect(result, { depth: null, colors: true }));
這將為您提供已解析的 XML 對象的詳細(xì)視圖,包括所有嵌套屬性。
假設(shè)您希望從此解析的對象中訪問各個(gè)項(xiàng)目。為此,您可以遍歷每個(gè)嵌套項(xiàng)并記錄每個(gè)嵌套項(xiàng),如下所示:
const items = result.vehicles.item;
items.forEach(item => {
console.log('Name:', item.name[0]);
console.log('Description:', item.description[0]);
console.log('Models:', item.models[0].model[0]);
});
現(xiàn)在,我們已經(jīng)了解了兩個(gè)很棒的解析庫,xmldom
和 xml2js
,盡管如此,在解析過程中使用這兩者時(shí),有一些重要的權(quán)衡值得考慮。
對于初學(xué)者來說,xmldom提供了XML的DOM表示作為輸出。要訪問和操作這些數(shù)據(jù),您需要利用標(biāo)準(zhǔn)的DOM方法來遍歷DOM樹。
相反,xml2js
將 XML 直接轉(zhuǎn)換為 JavaScript 對象。這簡化了數(shù)據(jù)訪問和操作。這種方法更直觀,允許與數(shù)據(jù)直接交互,而無需導(dǎo)航 DOM 樹。
性能在所有軟件進(jìn)程中都很重要,包括 XML 解析。對于大型 XML 文檔,將其解析為 DOM 可能會(huì)消耗大量資源。特別是當(dāng) XML 深度嵌套時(shí),管理完整的 DOM 結(jié)構(gòu)可能會(huì)顯著降低處理速度。
相比之下,xml2js在解析和訪問數(shù)據(jù)時(shí)通常更加迅速,原因在于它直接將XML轉(zhuǎn)換為JavaScript對象,避免了產(chǎn)生DOM表示所帶來的額外開銷。這可以在主要讀取 XML 數(shù)據(jù)的應(yīng)用程序中獲得更好的性能。
在處理大型 XML 文件時(shí),將整個(gè)文檔加載到內(nèi)存中可能效率低下,并導(dǎo)致性能瓶頸。要有效地處理大型 XML 文件,您可以使用Stream
模塊以塊的形式處理 XML 數(shù)據(jù),而不是一次加載所有數(shù)據(jù)。
該模塊是一個(gè)內(nèi)置的 Node.js 模塊,它提供了一種處理流數(shù)據(jù)的方法。它使得您可以按較小的數(shù)據(jù)塊進(jìn)行讀取或?qū)懭氩僮?,這在處理大型文件或數(shù)據(jù)流時(shí)顯得尤為有用。
要測試 Stream 模塊,請繼續(xù)創(chuàng)建一個(gè)新文件并包含large.xml
內(nèi)容。理想情況下,它不是一個(gè)大型 XML 文件,但對于此演示,我們將使用它:
<?xml version="1.0" encoding="UTF-8"?>
<vehicles xmlns="http://example.com/vehicles">
<vehicle type="http://example.com/car">
<name>Cars</name>
<description>I love cars.</description>
<models>
<model>Range Rover</model>
<model>Corolla</model>
<model>BMW</model>
<model>Toyota</model>
<model>Tesla</model>
</models>
</vehicle>
<vehicle type="http://example.com/motorcycle">
<name>Motorcycles</name>
<description>I also enjoy riding motorcycles.</description>
<models>
<model>Harley-Davidson</model>
<model>Honda</model>
<model>Yamaha</model>
<model>Ducati</model>
<model>Triumph</model>
</models>
</vehicle>
<vehicle type="http://example.com/minivan">
<name>Minivans</name>
<description>Minivans .</description>
<models>
<model>Honda Odyssey</model>
<model>Toyota Sienna</model>
<model>Chrysler Pacifica</model>
<model>Kia Carnival</model>
<model>Dodge Grand Caravan</model>
</models>
</vehicle>
</vehicles>
接下來,創(chuàng)建一個(gè)在同一目錄中調(diào)用的新文件test-stream.js
。將以下代碼復(fù)制并粘貼到該文件中。
此外,由于xml2js
在處理大型 XML 數(shù)據(jù)方面做得很好,我們可以輕松地將兩者結(jié)合起來,如下所示:
import fs from 'fs';
import { Parser } from 'xml2js';
import util from 'util';
const parser = new Parser();
const readStream = fs.createReadStream('large.xml', 'utf8');
readStream.on('data', (chunk) => {
parser.parseString(chunk, (err, result) => {
if (err) {
console.error('Error parsing XML:', err);
return;
}
console.log('Parsed data:', util.inspect(result, { depth: null, colors: true }));
});
});
readStream.on('end', () => {
console.log('process completed');
});
readStream.on('error', (err) => {
console.error('Error:', err);
});
在此示例中,我們從庫中導(dǎo)入fs
模塊和parseString
函數(shù)。我們創(chuàng)建一個(gè)新實(shí)例,該parseString.Parser
實(shí)例將用于解析 XML 數(shù)據(jù)。
接下來,我們使用 fs.createReadStream
來創(chuàng)建一個(gè)讀取流,并傳遞文件路徑(例如 'large.xml'
)和編碼(例如 'utf8'
)。這個(gè)讀取流將會(huì)以塊的形式來讀取文件。
在讀取流(readStream
)上監(jiān)聽'data'
事件以接收新的數(shù)據(jù)塊,并使用某個(gè)解析器(可能是xml2js
或類似的庫中的parseString
方法)來解析這些數(shù)據(jù)塊。
使用 command 啟動(dòng)節(jié)點(diǎn)服務(wù)器,在node test-stream.js
終端中查看結(jié)果。
此實(shí)現(xiàn)能夠無需一次性將整個(gè)大型 XML 文件加載到內(nèi)存中,而是通過讀取、處理和解析較小的數(shù)據(jù)塊來有效地處理該示例文件。
對于生產(chǎn)應(yīng)用程序,XML 文件可能比我們的示例大得多。這些數(shù)據(jù)塊通常需要在被使用前進(jìn)行適當(dāng)?shù)奶幚?。如果不加以注意,它們可能?huì)給您的應(yīng)用程序帶來沉重的負(fù)擔(dān),從而導(dǎo)致整體性能下降。有效地處理大型 XML 文件對于保持系統(tǒng)平穩(wěn)運(yùn)行非常重要。
使用流讀取和解析數(shù)據(jù)有助于避免這些問題。您還可以使用 Sax.js 等包,它將 XML 作為流進(jìn)行處理。這些方法可讓您更高效地處理大型 XML 文件,從而保持應(yīng)用程序的響應(yīng)速度。
讓我們換個(gè)方向,探討一下如何從零開始創(chuàng)建一個(gè)XML文件,這涉及將數(shù)據(jù)寫入XML文件中。整個(gè)流程首先是構(gòu)建出XML的結(jié)構(gòu),接著再將其序列化為具體的文件。
您可以使用一些庫來實(shí)現(xiàn)此目的,包括 xml2js
和 xmldom
用于更復(fù)雜的 XML 生成。
讓我們看一個(gè)使用 xml2jsBuilder
,此庫提供了一個(gè)類,可以輕松地將 JavaScript 對象轉(zhuǎn)換為 XML。
在此示例中,創(chuàng)建一個(gè)名為 write-xml.js
的新文件。我們將使用此文件來寫入 XML 數(shù)據(jù)。
首先,從 fs
中導(dǎo)入Builder
模塊和xml2js
類。
import fs from 'fs';
import { Builder } from 'xml2js';
接下來,創(chuàng)建一個(gè) JavaScript 對象,該對象表示要?jiǎng)?chuàng)建的 XML 結(jié)構(gòu)。此對象應(yīng)具有與我們要生成的 XML 文件相同的結(jié)構(gòu)。
const obj = {
vehicles: {
item: [
{
$: { name: 'Car' },
carDetails: 'Details about the car'
},
{
$: { name: 'Bike' },
bikeDetails: 'Details about the bike'
}
]
}
};
現(xiàn)在,使用實(shí)例將 JavaScript 對象轉(zhuǎn)換為 XML 字符串,如下所示:Builder
const builder = new Builder();
const xml = builder.buildObject(obj);
最后,使用 :fs.writeFileSync
fs.writeFileSync('output.xml', xml, 'utf8');
console.log('XML file written.');
沒錯(cuò)!這就是利用xml2js庫從頭開始創(chuàng)建XML文件的方式。雖然這只是一個(gè)簡單的例子,但它著重展示了將數(shù)據(jù)寫入XML文件的基本流程。
有許多工具可用于解析 XML。無論您使用的是小文件還是大文件,都要記住以下幾個(gè)關(guān)鍵點(diǎn),以及 XML 解析的一些常見問題以及如何修復(fù)它們:
XML 解析有許多實(shí)際用途。您可能會(huì)使用 JavaScript 和 Node.js 來進(jìn)行網(wǎng)頁抓取,或者處理更復(fù)雜的應(yīng)用程序中的 XML 數(shù)據(jù)。您在這里掌握的技能,將會(huì)成為您在未來JavaScript項(xiàng)目中處理結(jié)構(gòu)化數(shù)據(jù)時(shí)堅(jiān)實(shí)的基石。
原文鏈接:https://blog.apify.com/javascript-parse-xml/
node.js + express + docker + mysql + jwt 實(shí)現(xiàn)用戶管理restful api
nodejs + mongodb 編寫 restful 風(fēng)格博客 api
表格插件wpDataTables-將 WordPress 表與 Google Sheets API 連接
手把手教你用Python和Flask創(chuàng)建REST API
使用 Django 和 Django REST 框架構(gòu)建 RESTful API:實(shí)現(xiàn) CRUD 操作
ASP.NET Web API快速入門介紹
2024年在線市場平臺的11大最佳支付解決方案
完整指南:如何在應(yīng)用程序中集成和使用ChatGPT API
選擇AI API的指南:ChatGPT、Gemini或Claude,哪一個(gè)最適合你?