Comment joindre deux collections (LINQ to XML)
Un fichier XSD peut établir des relations dans un fichier XML pour permettre la jonction d’éléments afin de créer de nouveaux types d’éléments. Cet article fournit un exemple pour C# et Visual Basic qui joint des éléments et crée un document XML.
Un élément ou attribut dans un document XML peut parfois faire référence à un autre élément ou attribut. Par exemple, le document XML Exemple de fichier XML : Clients et commandes contient une liste de clients et une liste de commandes. Chaque élément Customer
a un attribut CustomerID
et chaque élément Order
contient un élément CustomerID
. La valeur de l’élément CustomerID
dans un élément Order
fait référence à l’élément Customer
qui a une valeur d’attribut CustomerID
correspondante.
L’article Exemple de fichier XSD : Clients et commandes contient un XSD qui peut servir à valider le document Customers and orders
. Il utilise les fonctionnalités xs:key
et xs:keyref
de XSD pour déterminer que l’attribut CustomerID
de l’élément Customer
est une clé et pour établir une relation entre la clé et l’élément CustomerID
des élémentsOrder
.
Avec LINQ to XML, vous pouvez tirer parti de cette relation en utilisant la clause join
pour joindre les informations client aux informations sur les commandes.
Pour obtenir des informations détaillées sur join
, consultez Opérations de jointure (C#) et Opérations de jointure (Visual Basic).
Notes
Les jointures sont effectuées à l’aide de recherches linéaires. Il n’existe aucun index pour améliorer les performances de recherche.
Exemple : créer un document XML avec Customer
et des éléments Order
joints
L’exemple suivant génère un nouveau document XML qui joint les éléments Customer
de l’Exemple de fichier XML : Clients et commandes aux éléments Order
, et inclut l’élément CompanyName
dans les commandes.
Avant d’exécuter la requête, l’exemple vérifie que le document est conforme au schéma dans Exemple de fichier XSD : Clients et commandes. Cela permet de s’assurer que la clause de jointure fonctionnera.
La requête sélectionne uniquement les commandes pour les clients dont le CustomerID
est supérieur à « K ». Elle projette de nouveaux éléments Order
qui contiennent les informations relatives aux clients dans chaque commande.
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", "CustomersOrders.xsd");
Console.Write("Attempting to validate, ");
XDocument custOrdDoc = XDocument.Load("CustomersOrders.xml");
bool errors = false;
custOrdDoc.Validate(schemas, (o, e) =>
{
Console.WriteLine("{0}", e.Message);
errors = true;
});
Console.WriteLine("custOrdDoc {0}", errors ? "did not validate" : "validated");
if (!errors)
{
// Join customers and orders, and create a new XML document with
// a different shape.
// The new document contains orders only for customers with a
// CustomerID > 'K'
XElement custOrd = custOrdDoc.Element("Root");
XElement newCustOrd = new XElement("Root",
from c in custOrd.Element("Customers").Elements("Customer")
join o in custOrd.Element("Orders").Elements("Order")
on (string)c.Attribute("CustomerID") equals
(string)o.Element("CustomerID")
where ((string)c.Attribute("CustomerID")).CompareTo("K") > 0
select new XElement("Order",
new XElement("CustomerID", (string)c.Attribute("CustomerID")),
new XElement("CompanyName", (string)c.Element("CompanyName")),
new XElement("ContactName", (string)c.Element("ContactName")),
new XElement("EmployeeID", (string)o.Element("EmployeeID")),
new XElement("OrderDate", (DateTime)o.Element("OrderDate"))
)
);
Console.WriteLine(newCustOrd);
}
Public Class Program
Public Shared errors As Boolean = False
Public Shared Function LamValidEvent(ByVal o As Object, _
ByVal e As ValidationEventArgs) As Boolean
Console.WriteLine("{0}", e.Message)
errors = True
End Function
Shared Sub Main()
Dim schemas As New XmlSchemaSet()
schemas.Add("", "CustomersOrders.xsd")
Console.Write("Attempting to validate, ")
Dim custOrdDoc As XDocument = XDocument.Load("CustomersOrders.xml")
custOrdDoc.Validate(schemas, Function(o, e) LamValidEvent(0, e))
If errors Then
Console.WriteLine("custOrdDoc did not validate")
Else
Console.WriteLine("custOrdDoc validated")
End If
If Not errors Then
'Join customers and orders, and create a new XML document with
' a different shape.
'The new document contains orders only for customers with a
' CustomerID > 'K'.
Dim custOrd As XElement = custOrdDoc.<Root>.FirstOrDefault
Dim newCustOrd As XElement = _
<Root>
<%= From c In custOrd.<Customers>.<Customer> _
Join o In custOrd.<Orders>.<Order> _
On c.@CustomerID Equals o.<CustomerID>.Value _
Where c.@CustomerID.CompareTo("K") > 0 _
Select _
<Order>
<CustomerID><%= c.@CustomerID %></CustomerID>
<%= c.<CompanyName> %>
<%= c.<ContactName> %>
<%= o.<EmployeeID> %>
<%= o.<OrderDate> %>
</Order> _
%>
</Root>
Console.WriteLine(newCustOrd)
End If
End Sub
End Class
Cet exemple produit la sortie suivante :
Attempting to validate, custOrdDoc validated
<Root>
<Order>
<CustomerID>LAZYK</CustomerID>
<CompanyName>Lazy K Kountry Store</CompanyName>
<ContactName>John Steel</ContactName>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-03-21T00:00:00</OrderDate>
</Order>
<Order>
<CustomerID>LAZYK</CustomerID>
<CompanyName>Lazy K Kountry Store</CompanyName>
<ContactName>John Steel</ContactName>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-05-22T00:00:00</OrderDate>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<CompanyName>Let's Stop N Shop</CompanyName>
<ContactName>Jaime Yorres</ContactName>
<EmployeeID>1</EmployeeID>
<OrderDate>1997-06-25T00:00:00</OrderDate>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<CompanyName>Let's Stop N Shop</CompanyName>
<ContactName>Jaime Yorres</ContactName>
<EmployeeID>8</EmployeeID>
<OrderDate>1997-10-27T00:00:00</OrderDate>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<CompanyName>Let's Stop N Shop</CompanyName>
<ContactName>Jaime Yorres</ContactName>
<EmployeeID>6</EmployeeID>
<OrderDate>1997-11-10T00:00:00</OrderDate>
</Order>
<Order>
<CustomerID>LETSS</CustomerID>
<CompanyName>Let's Stop N Shop</CompanyName>
<ContactName>Jaime Yorres</ContactName>
<EmployeeID>4</EmployeeID>
<OrderDate>1998-02-12T00:00:00</OrderDate>
</Order>
</Root>