Использование XmlProvider и обновление xml приводит к неправильному формату пространства имен

#xml #.net-core #f# #xsd

Вопрос:

Я использую XmlProvider и пытаюсь внести некоторые изменения в xml-файл.

Моя проблема в том, что при записи в файл изменяется формат пространства имен. Я попробовал два метода, где первый метод дает мне правильный формат, но я не могу использовать его для более сложных обновлений, таких как замена всех строк счета-фактуры новыми строками счетов-фактур.

Как я могу обновить/сохранить, чтобы формат был похож на xml, предоставленный поставщику?

Общий код:

 
open System
open System.Xml.Linq
open FSharp.Data
let cbc = XNamespace.Get("urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2")
let cac = XNamespace.Get("urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2")

type Invoice = XmlProvider<"""
<ehf:Invoice xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:ehf="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  <cbc:ID>5584-2021-2</cbc:ID>
  <cac:InvoiceLine>
    <cbc:ID>1a</cbc:ID>
    <cbc:Note>Note</cbc:Note>
    <cac:OrderLineReference>
      <cbc:LineID>1</cbc:LineID>
    </cac:OrderLineReference>
    <cac:Item>
      <cbc:Name>Item 1</cbc:Name>
    </cac:Item>
  </cac:InvoiceLine>
  <cac:InvoiceLine>
    <cbc:ID>1b</cbc:ID>
    <cbc:Note>Note</cbc:Note>
    <cac:OrderLineReference>
      <cbc:LineID>2</cbc:LineID>
    </cac:OrderLineReference>
    <cac:Item>
      <cbc:Name>Item 2</cbc:Name>
    </cac:Item>
  </cac:InvoiceLine>
</ehf:Invoice>
""">
 

Первый метод (результат выглядит так, как я хочу):

 invoice.XElement.SetElementValue(cbc   "ID", "New id")
printfn $"{invoice |> string}"
//<?xml version="1.0" encoding="utf-8"?>
//<ehf:Invoice xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:ehf="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
//  <cbc:ID>New id</cbc:ID>
//  <cac:InvoiceLine>
//    <cbc:ID>1a</cbc:ID>
//    <cbc:Note>Note</cbc:Note>
//    <cac:OrderLineReference>
//      <cbc:LineID>1</cbc:LineID>
//    </cac:OrderLineReference>
//    <cac:Item>
//      <cbc:Name>Item 1</cbc:Name>
//    </cac:Item>
//  </cac:InvoiceLine>
//  <cac:InvoiceLine>
//    <cbc:ID>1b</cbc:ID>
//    <cbc:Note>Note</cbc:Note>
//    <cac:OrderLineReference>
//      <cbc:LineID>2</cbc:LineID>
//    </cac:OrderLineReference>
//    <cac:Item>
//      <cbc:Name>Item 2</cbc:Name>
//    </cac:Item>
//  </cac:InvoiceLine>
//</ehf:Invoice>
 

Второй медтод (дает мне неправильный формат пространства имен):

 let line = invoice.InvoiceLines.[0]
let newLine = Invoice.InvoiceLine(
    "New id",
    line.Note,
    line.OrderLineReference,
    line.Item
    )
let changedInvoice = Invoice.Invoice(
      invoice.Id,
      [|newLine|]
      )
printfn $"{changedInvoice |> string}"

//<?xml version="1.0" encoding="utf-8"?>
//<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
//  <ID xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">New id</ID>
//  <InvoiceLine xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
//    <ID xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">New id</ID>
//    <Note xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">Note</Note>
//    <OrderLineReference>
//      <LineID xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">1</LineID>
//    </OrderLineReference>
//    <Item>
//      <Name xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">Item 1</Name>
//    </Item>
//  </InvoiceLine>
//</Invoice>
 

Ответ №1:

Проблема в том, что вновь созданный измененный счет-фактура не имеет атрибутов верхнего уровня xmlns , которые содержатся в исходном документе и определяют префиксы пространства имен. Вы можете исправить это, добавив их обратно после создания нового changedInvoice :

 let cbc = XNamespace.Get "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
let cac = XNamespace.Get "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" 
let ext = XNamespace.Get "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" 
let ehf = XNamespace.Get "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
changedInvoice.XElement.SetAttributeValue(XNamespace.Xmlns   "cbc", cbc)
changedInvoice.XElement.SetAttributeValue(XNamespace.Xmlns   "cac", cac)
changedInvoice.XElement.SetAttributeValue(XNamespace.Xmlns   "ext", ext)
changedInvoice.XElement.SetAttributeValue(XNamespace.Xmlns   "ehf", ehf)
changedInvoice.XElement.ToString()
 

Или, возможно, более простой подход-скопировать их из исходного счета-фактуры:

 for a in invoice.XElement.Attributes() do
  changedInvoice.XElement.SetAttributeValue(a.Name, a.Value)
changedInvoice.XElement.ToString()