Continuamos con esta serie sobre LINQ y la lectura de archivos XML y JSON. Ahora profundizaremos un poco con las operaciones básicas que podemos realizar:
- Where: Filtrar.
- Select: Proyecta campos.
- OrderBy: Ordenar.
- GroupBy: Agrupar y contar.
- Join: Unir colecciones.
- Any: Comprobar existencia.
- All: Comprobar condición en todos.
- Count: Devolver cantidad.
Consultas en archivos XML con LINQ
Realizaremos algunas consultas teniendo como entrada el siguiente archivo XML:
empleados.xml
<?xml version="1.0" encoding="UTF-8"?>
<Empleados>
<Empleado>
<Id>4392552</Id>
<Nombre>Horacio</Nombre>
<Apellidos>Gomez Torres</Apellidos>
<Correo>horacio.gomez.tor@infotec.com</Correo>
<Salario>25000.00</Salario>
<Departamento>202</Departamento>
</Empleado>
<Empleado>
<Id>4292856</Id>
<Nombre>Veronica</Nombre>
<Apellidos>Uribe Gomora</Apellidos>
<Correo>veronica.uribe.gom@infotec.com</Correo>
<Salario>30000.00</Salario>
<Departamento>204</Departamento>
</Empleado>
<Empleado>
<Id>4701330</Id>
<Nombre>Karla</Nombre>
<Apellidos>Perez Perez</Apellidos>
<Correo>karla.perez.per@infotec.com</Correo>
<Salario>28000.00</Salario>
<Departamento>200</Departamento>
</Empleado>
<Empleado>
<Id>4701366</Id>
<Nombre>Juan</Nombre>
<Apellidos>Archundia Lara</Apellidos>
<Correo>juan.archundia.lar@infotec.com</Correo>
<Salario>38000.00</Salario>
<Departamento>204</Departamento>
</Empleado>
</Empleados>
Mapearemos las etiquetas XML en una clase C#.
Empleado.cs
using System.Xml.Serialization;
namespace model
{
public class Empleado
{
public string Id { get; set; } = string.Empty;
public string Nombre { get; set; } = string.Empty;
public string Apellidos { get; set; } = string.Empty;
public string Correo { get; set; } = string.Empty;
public decimal Salario { get; set; } = decimal.Zero;
public string Departamento { get; set; } = string.Empty;
}
[XmlRoot("Empleados")]
public class Empleados
{
[XmlElement("Empleado")]
public List<Empleado> Lista { get; set; }
}
}
En una entrega anterior vimos cómo consultar documentos XML.
El siguiente bloque es importante para serializar los datos a partir de un documento XML.
// Ruta del archivo XML
public static readonly string PATH_XML = "empleados.xml";
// Serializar datos
var serializer = new XmlSerializer(typeof(Empleados));
// Lectura del XML
using var reader = new StreamReader(PATH_XML);
Comenzaremos con la operación Where:
Console.WriteLine("Empleados mejor pagados:");
var empleadosBienPagados = from emp in empleados.Lista
where emp.Salario > 28000
select emp;
foreach (var emp in empleadosBienPagados)
{
Console.WriteLine($"{emp.Nombre} - {emp.Salario}");
}
En SQL sería:
SELECT *
FROM empleados
WHERE Salario > 28000;
Continuamos con la operación Select:
Console.WriteLine("Nombre y correo:");
var contactosDev = from dev in empleados.Lista
select new { dev.Nombre, dev.Correo };
foreach (var emp in contactosDev)
{
Console.WriteLine($"{emp.Nombre} - {emp.Correo}");
}
En SQL sería:
SELECT Nombre, Correo
FROM empleados;
Continuamos con la operación OrderBy:
Console.WriteLine("Empleados [por salario ascendente]:");
var empleadosOrdenados = from emp in empleados.Lista
orderby emp.Salario
select emp;
foreach (var emp in empleadosOrdenados)
{
Console.WriteLine($"{emp.Nombre} {emp.Apellidos}, Depto: {emp.Departamento} , Salario: {emp.Salario}");
}
En SQL sería:
SELECT Nombre, Apellidos, Departamento, Salario
FROM empleados
ORDER BY Salario ASC;
Continuamos con la operación GroupBy y Count:
Console.WriteLine("Agrupar empleados por departamento:");
var empleadosPorDepto = from emp in empleados.Lista
group emp by emp.Departamento into deptGroup
select new
{
Departamento = deptGroup.Key,
Cantidad = deptGroup.Count()
};
foreach (var emp in empleadosPorDepto)
{
Console.WriteLine($"Departamento: {emp.Departamento} , Cantidad: {emp.Cantidad}");
}
En SQL sería:
SELECT Departamento, COUNT(*) AS Cantidad
FROM empleados
GROUP BY Departamento;
Para el conteo (COUNT) sería:
SELECT COUNT(*) AS TotalEmpleados
FROM empleados;
Continuamos con la operación Any:
bool hayAltosSueldos = empleados.Lista.Any(e => e.Salario > 30000);
if(hayAltosSueldos)
{
Console.WriteLine("Existe al menos un empleado con un salario relativamente grande.");
}
En SQL sería:
SELECT CASE
WHEN EXISTS (SELECT 1 FROM empleados WHERE Salario > 30000)
THEN 'TRUE'
ELSE 'FALSE'
END AS HayAltosSueldos;
Finalizamos con la operación All:
bool todosConCorreoEdu = empleados.Lista.All(d => d.Correo.EndsWith("infotec.com"));
if(todosConCorreoEdu)
{
Console.WriteLine("Todos los empleados tienen correo institucional.");
}
En SQL sería:
SELECT CASE
WHEN NOT EXISTS (
SELECT 1 FROM empleados
WHERE Correo NOT LIKE '%infotec.com'
)
THEN 'TRUE'
ELSE 'FALSE'
END AS TodosConCorreoInstitucional;
Programa completo:
Program.cs
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Xml.Linq;
using model;
using System.Xml.Serialization;
class Program
{
public static readonly string PATH_XML = "empleados.xml";
static void Main()
{
var serializer = new XmlSerializer(typeof(Empleados));
using var reader = new StreamReader(PATH_XML);
Empleados empleados = (Empleados)serializer.Deserialize(reader);
if(empleados != null)
{
Console.WriteLine("Empleados mejor pagados:");
var empleadosBienPagados = from emp in empleados.Lista
where emp.Salario > 28000
select emp;
foreach (var emp in empleadosBienPagados)
{
Console.WriteLine($"{emp.Nombre} - {emp.Salario}");
}
Console.WriteLine("Nombre y correo:");
var contactosDev = from dev in empleados.Lista
select new { dev.Nombre, dev.Correo };
foreach (var emp in contactosDev)
{
Console.WriteLine($"{emp.Nombre} - {emp.Correo}");
}
Console.WriteLine("Empleados [por salario ascendente]:");
var empleadosOrdenados = from emp in empleados.Lista
orderby emp.Salario
select emp;
foreach (var emp in empleadosOrdenados)
{
Console.WriteLine($"{emp.Nombre} {emp.Apellidos}, Depto: {emp.Departamento} , Salario: {emp.Salario}");
}
Console.WriteLine("Agrupar empleados por departamento:");
var empleadosPorDepto = from emp in empleados.Lista
group emp by emp.Departamento into deptGroup
select new
{
Departamento = deptGroup.Key,
Cantidad = deptGroup.Count()
};
foreach (var emp in empleadosPorDepto)
{
Console.WriteLine($"Departamento: {emp.Departamento} , Cantidad: {emp.Cantidad}");
}
bool hayAltosSueldos = empleados.Lista.Any(e => e.Salario > 30000);
if(hayAltosSueldos)
{
Console.WriteLine("Existe al menos un empleado con un salario relativamente grande.");
}
bool todosConCorreoEdu = empleados.Lista.All(d => d.Correo.EndsWith("infotec.com"));
if(todosConCorreoEdu)
{
Console.WriteLine("Todos los empleados tienen correo institucional.");
}
}
}
}
Construimos y ejecutamos:
$ dotnet build
$ dotnet run
Salida:
Empleados mejor pagados:
Veronica - 30000.00
Juan - 38000.00
Nombre y correo:
Horacio - horacio.gomez.tor@infotec.com
Veronica - veronica.uribe.gom@infotec.com
Karla - karla.perez.per@infotec.com
Juan - juan.archundia.lar@infotec.com
Empleados [por salario ascendente]:
Horacio Gomez Torres, Depto: 202 , Salario: 25000.00
Karla Perez Perez, Depto: 200 , Salario: 28000.00
Veronica Uribe Gomora, Depto: 204 , Salario: 30000.00
Juan Archundia Lara, Depto: 204 , Salario: 38000.00
Agrupar empleados por departamento:
Departamento: 202 , Cantidad: 1
Departamento: 204 , Cantidad: 2
Departamento: 200 , Cantidad: 1
Existe al menos un empleado con un salario relativamente grande.
Todos los empleados tienen correo institucional.
¡Hemos creado consultas básicas con LINQ!
Continuaremos con esta serie sobre C# y LINQ.
Enlaces:
https://codemonkeyjunior.blogspot.com/2026/06/linq-consultando-documentos-json.html
https://codemonkeyjunior.blogspot.com/2025/12/linq-consultando-documentos-xml.html
https://codemonkeyjunior.blogspot.com/2025/11/linq-un-lenguaje-de-consulta-para-c.html