Procedimiento para combinar dos colecciones (LINQ to XML)
Un archivo XSD puede establecer relaciones en un archivo XML para permitir la combinación de elementos para crear nuevos tipos de elementos. En este artículo se proporciona un ejemplo para C# y Visual Basic que combina elementos y crea un nuevo documento XML.
A veces, un elemento o atributo de un documento XML puede hacer referencia a otro elemento o atributo. Por ejemplo, el documento XML Archivo XML de muestra: clientes y pedidos contiene una lista de clientes y una lista de pedidos. Cada Customer
elemento tiene un CustomerID
atributo y cada Order
elemento contiene un CustomerID
elemento. El CustomerID
valor de elemento de un Order
elemento hace referencia al Customer
elemento que tiene un valor de atributo coincidente CustomerID
.
En el artículo Documento de muestra XSD: Clientes y pedidos se incluye un XSD que se puede usar para validar este documento Customers and orders
. Usa las características xs:key
y xs:keyref
de XSD para establecer que el atributo CustomerID
del elemento Customer
es una clave, y para establecer una relación entre la clave y el CustomerID
elemento de los Order
elementos.
Con LINQ to XML, puedes aprovechar esta relación mediante la join
cláusula para unir la información del cliente para solicitar información.
Para obtener información más detallada sobre join
, consulta Operaciones de unión (C#) y Operaciones de combinación (Visual Basic).
Nota
Las combinaciones se realizan mediante búsquedas lineales. No hay índices para aumentar el rendimiento de la búsqueda.
Ejemplo: Crear un nuevo documento XML que tenga Customer
elementos y Order
unidos
En el ejemplo siguiente se genera un nuevo documento XML que combina los Customer
elementos del archivo XML de ejemplo: Clientes y pedidos a los Order
elementos e incluye el CompanyName
elemento en los pedidos.
Antes de ejecutar la consulta, el ejemplo valida que el documento cumple el esquema de Sample XSD File: Customers and Orders (Archivo XSD de ejemplo: Clientes y pedidos). Esto garantiza que la cláusula de combinación funcionará.
La búsqueda selecciona sólo los pedidos de los clientes con un atributo CustomerID
mayor que «K». Proyecta nuevos elementos Order
que contienen la información de cliente en cada pedido.
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
Este ejemplo produce el siguiente resultado:
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>