Синтаксический анализ XML-файла, созданного MS Word, на C#

#c# #xml #parsing #xpath #ms-word

#c# #xml #синтаксический анализ #xpath #ms-word

Вопрос:

Итак, у меня есть клиент (это может быть только от правительства), у которого есть куча документов MS Word, которые они хотят ввести в базу данных, и, если не считать ручного ввода, я чувствую, что лучшим вариантом будет преобразовать их в XML и проанализировать их с помощью служебной программы.

У меня есть утилита для этого, используя код, найденный здесь, в stackoverflow:

 Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
object oMissing = System.Reflection.Missing.Value;

DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath("\testfiles"));
FileInfo[] wordFiles = dirInfo.GetFiles("*.doc");

word.Visible = false;
word.ScreenUpdating = false;

XmlDocument xmlDoc = new XmlDocument();

foreach(FileInfo wordFile in wordFiles)
{
    Object filename = (Object)wordFile.FullName;
    Document doc = word.Documents.Open(ref filename, ref oMissing,
         ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
         ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
         ref oMissing, ref oMissing, ref oMissing, ref oMissing);

    doc.Activate();

    object outputFileName = wordFile.FullName.Replace(".doc", ".xml");
    object fileFormat = WdSaveFormat.wdFormatXML;

    doc.SaveAs(ref outputFileName, ref fileFormat, ref oMissing,
         ref oMissing, ref oMissing, ref oMissing, ref oMissing,
         ref oMissing, ref oMissing, ref oMissing, ref oMissing,
         ref oMissing, ref oMissing, ref oMissing, ref oMissing);

    object saveChanges = WdSaveOptions.wdDoNotSaveChanges;
    ((_Document)doc).Close(ref saveChanges, ref oMissing, ref oMissing);
    doc = null;

    xmlDoc.Load(outputFileName.ToString());
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
    nsmgr.AddNamespace("w", "http://schemas.microsoft.com/office/word/2003/wordml");

    XmlNodeList node = xmlDoc.SelectNodes("//w:document/descendant::w:t|//w:document/descendant::w:p|//w:document/descendant::w:tab", nsmgr);
}

((_Application)word).Quit(ref oMissing, ref oMissing, ref oMissing);
word = null;
  

Теперь мои XML-файлы выглядят следующим образом:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?mso-application progid="Word.Document"?>
<w:wordDocument xmlns:aml="http://schemas.microsoft.com/aml/2001/core" 
            xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" 
            xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:o="urn:schemas-microsoft-com:office:office" 
            xmlns:v="urn:schemas-microsoft-com:vml" 
            xmlns:w10="urn:schemas-microsoft-com:office:word" 
            xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml" 
            xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint" 
            xmlns:wsp="http://schemas.microsoft.com/office/word/2003/wordml/sp2" 
            xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core" 
            w:macrosPresent="no" 
            w:embeddedObjPresent="no" 
            w:ocxPresent="no" 
            xml:space="preserve">
<w:ignoreSubtree w:val="http://schemas.microsoft.com/office/word/2003/wordml/sp2"/>
<o:DocumentProperties>
  ...
</o:DocumentProperties>
<w:fonts>
  ...
</w:fonts>
<w:lists>
  ...
</w:lists>
<w:styles>
  ...
</w:styles>
<w:shapeDefaults>...</w:shapeDefaults>
<w:docPr>...</w:docPr>
<w:body>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775">
    <w:pPr>
      <w:tabs>
        <w:tab w:val="left" w:pos="3312"/>
        <w:tab w:val="left" w:pos="4032"/>
        <w:tab w:val="left" w:pos="5616"/>
      </w:tabs><w:ind w:right="-576"/>
    </w:pPr>
  </w:p>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775">
    <w:pPr>
      <w:jc w:val="center"/>
      <w:rPr>
        <w:b/>
      </w:rPr>
    </w:pPr>
    <w:r>
      <w:rPr>
        <w:b/>
      </w:rPr>
      <w:t>blah blah blach this is sample text</w:t>
    </w:r>
  </w:p>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775">
    <w:pPr>
      <w:jc w:val="center"/>
    </w:pPr>
    <w:r>
      <w:rPr>
        <w:b/>
      </w:rPr>
      <w:t>More sample text</w:t>
    </w:r>
  </w:p>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775"/>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775"/>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775"/>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775"/>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775">
    <w:r>
      <w:t>Sample Header</w:t>
    </w:r>
  </w:p>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775"/>
  <w:p wsp:rsidR="00B01775" wsp:rsidRDefault="00B01775">
    <w:pPr>
      <w:pStyle w:val="BodyText"/>
    </w:pPr>
    <w:r>
      <w:rPr>
        <w:snapToGrid w:val="off"/>
      </w:rPr>
      <w:t>Sample Body text.......</w:t>
    </w:r>
  </w:p>
 </w:body>
</w:wordDocument>
  

Я не профессионал, но я думаю, что здесь я довольно хорошо следую буквам закона, правильно объявив диспетчер пространств имен, так почему же тогда я получаю нулевое значение для узлов, которые я пытаюсь выбрать?

 XmlNodeList node = xmlDoc.SelectNodes("//w:document/descendant::w:t|//w:document/descendant::w:p|//w:document/descendant::w:tab", nsmgr);
  

Я что-то упустил?

Комментарии:

1. Я просто пропускаю другие дополнения к пространству имен? Конечно, мне не нужно добавлять их все только для обработки префикса «w»?

2. просто любопытно, а как насчет простого добавления их в БД в виде «двоичных» объектов, например, изображения?

3. Я бы С удовольствием это сделал, но на самом деле мы используем новую систему, чтобы помочь им перейти от бумажного к цифровому миру. Это реликвии, которые необходимо включить в новую систему.

4. имеет смысл. еще один вопрос … является ли Sharepoint вариантом? вы можете создавать библиотеки документов для хранения документов, и у него даже есть контроль версий с функцией возврата / возврата.

5. Я бы тоже хотел это сделать, но они меняют способ создания документов, поэтому вместо того, чтобы передавать документ-токен, веб-приложение сохранит информацию в БД (поскольку это стандартно для каждого документа), а затем сгенерирует документ только после всех изменений ибыли внесены изменения в базовый набор информации. Я знаю, это странно, но это мир, в котором я живу прямо сейчас.

Ответ №1:

Похоже, у вас неправильное имя узла в вашем выражении XPath. Замените все вхождения w:document на w:wordDocument . Так что это должно быть:

 XmlNodeList node = xmlDoc.SelectNodes("//w:wordDocument/descendant::w:t|//w:wordDocument/descendant::w:p|//w:wordDocument/descendant::w:tab", nsmgr);
  

Комментарии:

1. Вау, удивительно, что вы можете сделать, когда вы вырезаете и вставляете в конце дня и не выполняете проверку кода. Спасибо!