2016-11-03 4 views
1

Ich muss einige Tags und Attribute aus einem XML mit einer definierten Struktur lesen, aber da diese Dateien aus verschiedenen Quellen generiert werden können, können sie unterschiedliche Namespaces und Präfixe haben.C# XML mit mehreren Variablen-Namespaces lesen

Dies ist die erste Probe XML

<Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:Order-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <cbc:UBLVersionID>2.1</cbc:UBLVersionID> 
    <cbc:CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</cbc:CustomizationID> 
    <cbc:ID>ORD-001</cbc:ID> 
    <cbc:IssueDate>2016-10-01</cbc:IssueDate> 
    <cbc:OrderTypeCode listID="UNCL1001">221</cbc:OrderTypeCode> 
    <cac:ValidityPeriod> 
     <cbc:EndDate>2024-10-19</cbc:EndDate> 
    </cac:ValidityPeriod> 
    <cac:BuyerCustomerParty> 
     <cac:Party> 
      <cbc:EndpointID schemeID="IT:IPA">ITAK12MH</cbc:EndpointID> 
      <cac:PartyIdentification> 
       <cbc:ID schemeID="IT:VAT">01567570254</cbc:ID> 
      </cac:PartyIdentification> 
      <cac:PartyName> 
       <cbc:Name>A Custom Name</cbc:Name> 
      </cac:PartyName> 
     </cac:Party> 
    </cac:BuyerCustomerParty> 
</Order> 

Dies ist die zweite XML Probe mit unterschiedlichen Namensräumen und Präfixen, aber dieselbe Struktur (Tags, Attribute).

<ns10:Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ns2="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:ns3="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ns4="http://www.w3.org/2000/09/xmldsig#" xmlns:ns5="http://uri.etsi.org/01903/v1.3.2#" xmlns:ns6="urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2" xmlns:ns7="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2" xmlns:ns8="http://uri.etsi.org/01903/v1.4.1#" xmlns:ns9="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2" xmlns:ns10="urn:oasis:names:specification:ubl:schema:xsd:Order-2"> 
    <UBLVersionID>2.1</UBLVersionID> 
    <CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</CustomizationID> 
    <ID>ORD-001</ID> 
    <IssueDate>2016-10-01</IssueDate> 
    <OrderTypeCode listID="UNCL1001">221</OrderTypeCode> 
    <ns3:ValidityPeriod> 
     <EndDate>2024-10-19</EndDate> 
    </ns3:ValidityPeriod> 
    <ns3:BuyerCustomerParty> 
     <ns3:Party> 
      <EndpointID schemeID="IT:IPA">ITAK12MH</EndpointID> 
      <ns3:PartyIdentification> 
       <ID schemeID="IT:VAT">01567570254</ID> 
      </ns3:PartyIdentification> 
      <ns3:PartyName> 
       <Name>A Custom Name</Name> 
      </ns3:PartyName> 
     </ns3:Party> 
    </ns3:BuyerCustomerParty> 
</ns10:Order> 

Diese Dateien müssen das gleiche und so beide als gültig betrachtet werden.

Ein drittes Beispiel kann eine Datei ähnlich der zweiten sein, wo die Namespaces gleich sind, aber ihre Präfixe sind unterschiedlich. Offensichtlich ist es wichtig, dass das Präfix, mit dem der Namespace übereinstimmt, zu diesem bestimmten Tag gehört.

Ich habe keine Möglichkeit im Voraus zu wissen, welche Präfixe mit Namespaces verknüpft sind.

<aaa:Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:aaa="urn:oasis:names:specification:ubl:schema:xsd:Order-2" xmlns:bbb="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"> 
    <UBLVersionID>2.1</UBLVersionID> 
    <CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</CustomizationID> 
    <ID>ORD-001</ID> 
    <IssueDate>2016-10-01</IssueDate> 
    <OrderTypeCode listID="UNCL1001">221</OrderTypeCode> 
    <bbb:ValidityPeriod> 
     <EndDate>2024-10-19</EndDate> 
    </bbb:ValidityPeriod> 
    <bbb:BuyerCustomerParty> 
     <bbb:Party> 
      <EndpointID schemeID="IT:IPA">ITAK12MH</EndpointID> 
      <bbb:PartyIdentification> 
       <ID schemeID="IT:VAT">01567570254</ID> 
      </bbb:PartyIdentification> 
      <bbb:PartyName> 
       <Name>A Custom Name</Name> 
      </bbb:PartyName> 
     </bbb:Party> 
    </bbb:BuyerCustomerParty> 
</aaa:Order> 

Diese letzte Datei muss wie die anderen als gültig betrachtet werden.

Wie Sie sehen können, ist die Zuordnung zwischen den Tags und ihren Namespaces immer gleich. Die einzigen Dinge, die geändert werden, sind die Präfixe.

Mein tatsächlicher Code verwendet XDocument und XElement-Klassen, um die XML zu lesen, aber es kann der Weg sein, weil ich das genaue Präfix für jedes Tag wissen muss und da sie variieren können, funktioniert es nur mit dem ersten XML-Dateibeispiel.

Wie kann ich die XMLs lesen, ohne die Namespacepräfixe angeben zu müssen? Soll ich eine andere .NET-Bibliothek oder vielleicht eine andere verwenden?

Antwort

1

Mit LocalName können Sie es ohne Hinzufügen des Namespace verknüpfen.

//this is for <cbc:ID>ORD-001</cbc:ID> 
var element = doc.Root.Elements().Where(x => x.Name.LocalName == "ID").FirstOrDefault(); 

Wenn Sie in den verschachtelten Elementen hinwollen

var element = doc.Root.Elements().Where(x => x.Name.LocalName == "ValidityPeriod"). 
       Elements().Where(x=> x.Name.LocalName == "EndDate").FirstOrDefault(); 
+1

Funktioniert wie ein Charme! –

0

Ich brauche den genauen Präfix für jeden Tag wissen.

Nein, tun Sie nicht. Die Präfixe sind für den qualifizierten Namen eines Elements oder Attributs völlig irrelevant. Wenn Sie die XPath-Route verwenden möchten, lesen Sie nicht die Namespaces und Präfixe aus dem Dokument, um Ihren Namespace-Manager zu erstellen, und geben Sie sie selbst an, damit Sie wissen, was sie sind. Verwenden Sie dann diese in Ihrer Abfrage. Zum Beispiel funktioniert dies mit einem Ihrer XML-Dokumente:

var manager = new XmlNamespaceManager(new NameTable()); 

manager.AddNamespace("cbc", 
    "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"); 

var id = doc.Root.XPathSelectElement("cbc:ID", manager); 

Was würde ich ermutigen, ist jedoch, dass Sie XPath Graben. LINQ to XML ist so viel schöner. Und noch ein kurzer Hinweis, es gibt eine Überladung von XDocument.Load, die einen Stream akzeptiert. Es ist nicht notwendig, die XmlReader zu erstellen.Also:

XNamespace order = "urn:oasis:names:specification:ubl:schema:xsd:Order-2"; 
XNamespace cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"; 
XNamespace cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"; 

var doc = XDocument.Load(stream); 

var id = (string) doc.Elements(order + "Order") 
    .Elements(cbc + "ID") 
    .Single(); 

var issueDate = (DateTime) doc.Elements(order + "Order") 
    .Elements(cbc + "IssueDate") 
    .Single(); 

var buyerPartySchemeId = (string) doc.Descendants(cac + "BuyerCustomerParty") 
    .Descendants(cbc + "ID") 
    .Attributes("schemeID") 
    .Single(); 
+0

Mit Ihrem Ansatz muss ich alle Namespaces manuell initialisieren. Ich weiß nicht, welche Namespaces benötigt werden und auch wenn sie sich aus irgendeinem Grund ändern (neue Version oder so ...) muss ich den Code nochmal ändern. –

+0

@CheshireCat Sie wissen, was Sie daraus lesen möchten, damit Sie die Namespaces kennen. Wenn eine neue Version die Namespaces ändert, ändert sich nichts daran, wie die Elemente oder Attribute aufgerufen werden oder welche Typen sie haben. Wahrscheinlich müssen Sie den Code auf die gleiche Weise aktualisieren. –