мотивация
В предыдущем проекте возникло требование, которое требовало, чтобы клиент загружал документ Word, а затем сервер извлекал содержимое из указанного местоположения документа и сохранял его. Бэкэнд здесь - nodejs.Когда я начал получать это требование, я обнаружил, что у меня нет возможности начать, в основном потому, что я не имел дело с документами этого типа.Как его разобрать?В Excel есть связанные библиотеки, которые можно используется, и это очень просто.
идеи
После некоторого поиска я нашел файл в npm с именемadm-zip
Этот пакет может распаковывать документ Word. Исходный документ Word также можно распаковать. Я не знал об этом раньше. Следующий код может распаковать документ Word и дополнительно извлечь содержимое
var admZip = require('adm-zip');
const zip = new admZip('test.docx');
//将该docx解压到指定文件夹result下
zip.extractAllTo("./result", /*overwrite*/true);
Сначала мы создаем новый документ docx со следующим содержимым
Затем запустите приведенный выше код для распаковки и получите следующие файлы.Как видно из рисунка ниже, создается несколько папок.Содержимое слова фактически находится в файле document.xml в папке слова (исходный файл на самом деле исходный файл после распаковки здесь).все равно не пропало)
После ввода содержимого папки word
Продолжим открывать файл document.xml, чтобы узнать, что внутри? Обратите внимание, что вам нужно открыть его прямо в браузере, если вы откроете его в ide, весь отображаемый контент находится в одной строке и не может быть прочитан! Вышеприведенное изображение является лишь частью документа Word. Вы обнаружите, что в документе Word есть всего несколько абзацев текста, но XML представляет собой длинное обсуждение, что является нормальным при тщательном анализе. Полное имя xml: расширяемый язык разметки, предназначенный для передачи и хранения данных. Это всего лишь представление простого текста, а формат содержимого в Word постоянно меняется. Должен существовать способ эффективного описания формата этого содержимого, поэтому xml используется для описанияДавай попробуем测试文档
Четыре символа выделены полужирным шрифтом с изменяющимся цветом наклонным шрифтом, как показано ниже.
<w:b/>
означает полужирный текст,<w:i/>
Указывает, что текст наклонен,<w:color>
Указывает на цвет текста, поэтому эти 4 слова требуют для описания этих строк xml, так что неудивительно, что многословный xml
Извлечь содержимое
Как упоминалось выше, xml — это только представление текста.Мы можем прочитать содержимое всего xml с помощью следующего кода, и результатом будетstring
var contentXml = zip.readAsText("word/document.xml");
Далее ключевой момент. Как извлечь нужный нам контент? Ответ - регулярные выражения. Прежде всего, мы должны проанализировать структуру документа Word. Документ Word на самом деле состоит из файлов с именамиParagraph
Он состоит из абзацев, которые можно легко получить и изменить в vb.Официальный сайт порталакликните сюда
Так что же такоеParagraph
Ну, на самом деле это очень просто. Посмотрите внимательно на документ Word и увидите маленькие стрелки на картинке ниже. Содержимое перед каждой маленькой стрелкой представляет собой абзац, поэтому на картинке ниже их 16.Paragraph
, конечно, некоторые абзацы пусты и не имеют содержания
<w:p></w:p>
Такой тег представляет собой представленный абзац, некоторые из которых находятся посередине.<w:p>
Спрятаны в таблице, поэтому посмотрите первые 3 абзаца и последние 3 абзаца таблицы, которые соответствуют картинке выше
следовательно,Мы можем извлечь текст каждого абзаца и вернуть массив, каждый элемент является содержимым абзаца., так что содержимое всего слова может быть полностью проанализировано, ключ заключается в том, как извлечь каждый<w:p>
содержание, мы продолжаем расширять<w:p>
Наблюдение, как показано на рисунке ниже, обнаружило, что хотя контента много, текст на самом деле сохраняется в<w:t>
Посередине, чтобы мысль была ясна,Сначала используйте регулярные выражения для извлечения всего содержимого , а затем выполните дальнейшее регулярное извлечение содержимого каждого
, извлеките в нем все содержимое
специальный код
Ниже приведен конкретный код извлечения.
//参数是word文件名,第二个参数是回调表示解析完成
var parser = function parseWordDocument(absoluteWordPath,callback){
//返回内容的数组
var resultList = [];
//如果文件存在
fs.exists(absoluteWordPath, function(exists){
if(exists){
//解压缩
const zip = new admZip(absoluteWordPath);
//将document.xml(解压缩后得到的文件)读取为text内容
var contentXml = zip.readAsText("word/document.xml");
//正则匹配出对应的<w:p>里面的内容,方法是先匹配<w:p>,再匹配里面的<w:t>,将匹配到的加起来即可
//注意?表示非贪婪模式(尽可能少匹配字符),否则只能匹配到一个<w:p></w:p>
var matchedWP = contentXml.match(/<w:p.*?>.*?<\/w:p>/gi);
//继续匹配每个<w:p></w:p>里面的<w:t>,这里必须判断matchedWP存在否则报错
if(matchedWP){
matchedWP.forEach(function(wpItem){
//注意这里<w:t>的匹配,有可能是<w:t xml:space="preserve">这种格式,需要特殊处理
var matchedWT = wpItem.match(/(<w:t>.*?<\/w:t>)|(<w:t\s.[^>]*?>.*?<\/w:t>)/gi);
var textContent = '';
if(matchedWT){
matchedWT.forEach(function(wtItem){
//如果不是<w:t xml:space="preserve">格式
if(wtItem.indexOf('xml:space')===-1){
textContent+=wtItem.slice(5,-6);
}else{
textContent+=wtItem.slice(26,-6);
}
});
resultList.push(textContent)
}
});
//解析完成
callback(resultList)
}
}else{
callback(resultList)
}
});
};
Обратите внимание, что если перед абзацем есть пробел, то<w:t>
Формат другой, как следует, больше места в описании, поэтому требуется специальная обработка
Количество кода на самом деле очень мало.Ключ заключается в регулярном написании.Выходные результаты вышеуказанного извлечения документа docx следующие
Наконец, я написал этот инструмент в пакете npm, адрескликните сюда