Общие элементы поставщика типа F # XML

#xml #f# #xsd #type-providers #f#-data

#xml #f# #xsd #поставщики типов #f #-данные

Вопрос:

Спецификации XSD для файлов XML могут совместно использовать общие элементы. Если у меня есть несколько XML-файлов, которые совместно используют общий элемент, есть ли способ извлечь общий элемент без повторения кода для каждого типа файла XML?

Например: Существует ряд XML-файлов, определенных с помощью XSD, с общим элементом описания, но различными структурами содержимого в других местах. В описании есть подэлементы с такими параметрами, как автор, дата и т.д. Когда я создаю поставщика типов для каждого из XML-файлов, типы различаются, поэтому, если я хочу извлечь только раздел описания из каждого, код должен быть скопирован для каждого из типов.

XML-файл 1:

 <root>
  <description >
     <author> Me </author>     
  </description>
  <element > Data </element>
  <otherelement> Data </otherelement>
</root>
  

XML-файл 2:

 <root2>
  <description >
     <author> Me </author>     
  </description>
  <elem > Data </elem>
  <diffelem> Data </diffelem >
</root2>
  

Потребуется, чтобы код был чем-то вроде:

 type File1 = XmlProvider<""".file1.xml""">
type File2 = XmlProvider<""".file2.xml""">

let descript1 = 
    File1.GetSample().description.author   
let descript2 = 
    File2.GetSample().description.author    //duplicated code
  

В данном случае это просто, но становится более сложным с более длинным описанием и большим количеством типов файлов XML.

Есть ли способ обойти это? Может ли поставщик типов быть создан для подмножества XML-файла и извлекать только эти части, чтобы код можно было использовать повторно?

Ответ №1:

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

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

 <?xml version="1.0" encoding="utf-8"?>
<samples>
  <root>
    <description><author> Me </author></description>
    <element > Data </element>
    <otherelement> Data </otherelement>
  </root>
  <root2>
    <description ><author> Me </author></description>
    <elem > Data </elem>
    <diffelem> Data </diffelem >
  </root2>
</samples>
  

Теперь вы можете создать поставщика типов XML и сообщить ему, что ваш образец файла представляет собой список ( SampleIsList=true ) и что он должен использовать глобальное разрешение (это означает, что все названные элементы description будут обрабатываться как значения одного типа):

 type X = XmlProvider<"C:/temp/sample1.xml", SampleIsList=true, Global=true>
  

Теперь у вас есть корни с разными именами, что усложняет ситуацию, но теперь вы можете написать код, который получает <description> элемент из одного или другого корня:

 let i = X.Load("...")

let description = 
  match i.Root, i.Root2 with
  | Some r1, _ -> r1.Description
  | _, Some r2 -> r2.Description
  | _ -> failwith "Missing"
  

Это дает вам узел описания с author вспомогательным узлом, который вы можете получить для обоих ваших документов:

 description.Author