Eliminar etiquetas HTML y extraer texto en Power Query
TL;DR: El método más confiable para eliminar etiquetas HTML en Power Query es Html.Table([Columna], {{"texto", ":root"}}){0}[texto], que usa el parser HTML nativo del motor M para extraer solo el texto visible. Para nulos o HTML malformado, envolvelo en try ... otherwise null. Los métodos basados en Text.Replace funcionan para casos simples, pero fallan con HTML anidado o entidades encodeadas.
Cuando conectás Power BI a fuentes externas como SharePoint, Salesforce, Dynamics, sistemas de tickets o bases de datos heredadas, es habitual encontrar columnas de texto donde el contenido llegó desde un editor de texto enriquecido. El resultado en la fuente es algo así:
<div class="ExternalClass5796EA3C"><p><strong>Proyecto Alpha</strong> - Fase 2</p>
<p>Estado: <em>En revisión</em>. Fecha límite: 15/07/2026. </p>
<p>Contacto: <a href="mailto:ana@empresa.com">Ana García</a></p></div>
Lo que necesitás en tu modelo de Power BI es simplemente:
Proyecto Alpha - Fase 2. Estado: En revisión. Fecha límite: 15/07/2026. Contacto: Ana García
Acá van tres métodos, del más robusto al más simple.
Método 1: Html.Table con selector :root (recomendado)
Html.Table es una función nativa de M que toma una cadena de texto, la interpreta como HTML y extrae nodos usando selectores CSS. Para extraer todo el texto visible de cualquier bloque HTML, el selector :root captura el contenido de texto del nodo raíz completo:
Html.Table([Columna], {{"texto", ":root"}}){0}[texto]
Desglose:
– {{"texto", ":root"}} — define una tabla resultado con una columna llamada «texto» que usa el selector :root
– {0}[texto] — toma la primera fila de esa tabla y devuelve el valor de la columna «texto»
Fórmula completa como columna personalizada
= Table.AddColumn(
#"Paso anterior",
"Contenido limpio",
each try Html.Table([HtmlCol], {{"texto", ":root"}}){0}[texto] otherwise null,
type text
)
El try...otherwise null es esencial: si la celda es null, está vacía o contiene HTML inválido, devuelve null sin detener la consulta.
Ventajas de este método
- Elimina todas las etiquetas HTML, incluyendo anidadas y atributos
- Decodifica entidades HTML como
 (espacio no separable),&,<automáticamente - Funciona con HTML complejo de cualquier origen
Limitación
Si el HTML tiene múltiples párrafos, Html.Table devuelve varias filas (una por nodo de texto). El {0} solo toma la primera. Para concatenar todos los párrafos:
Text.Combine(
Html.Table([HtmlCol], {{"texto", ":root"}})[texto],
" "
)
Método 2: función reutilizable para toda la consulta
Si necesitás limpiar HTML en varias columnas, definí una función al inicio de la consulta:
let
LimpiarHTML = (html as nullable text) as nullable text =>
if html = null or html = ""
then null
else try
Text.Combine(
Html.Table(html, {{"t", ":root"}})[t],
" "
)
otherwise null,
Origen = ..., // tu fuente de datos
Limpio = Table.TransformColumns(
Origen,
{
{"Descripcion", LimpiarHTML, type text},
{"Comentarios", LimpiarHTML, type text},
{"Notas", LimpiarHTML, type text}
}
)
in
Limpio
Esto aplica la misma limpieza a varias columnas en un solo paso con Table.TransformColumns.
Método 3: Text.Replace para HTML simple
Para casos donde el HTML es predecible y tiene pocas etiquetas (por ejemplo, solo <br> y <p>), podés usar reemplazos en cadena:
let
SinBR = Text.Replace([Columna], "<br>", " "),
SinBR2 = Text.Replace(SinBR, "<br/>", " "),
SinP = Text.Replace(SinBR2, "</p>", " "),
SinDiv = Text.Replace(SinP, "<div>", ""),
// ... continuar para cada etiqueta conocida
Limpio = Text.Trim(SinDiv)
in
Limpio
Problema: este enfoque no escala. Cada etiqueta nueva que aparezca en los datos requiere un nuevo reemplazo. Con atributos (<p class="...">) el enfoque falla porque tenés que anticipar todos los valores posibles. No es recomendable para datos reales de SharePoint u otras fuentes ricas.
Caso práctico: datos de SharePoint con HTML
SharePoint almacena los campos de texto enriquecido con clases CSS propias (ExternalClass...) y entidades encodeadas (: para :,   para espacio no separable). El Método 1 maneja todo esto sin configuración adicional.
let
// Conectar a lista de SharePoint
Origen = SharePoint.Tables("https://tuempresa.sharepoint.com/sites/Proyectos"),
Lista = Origen{[Name="Incidencias"]}[Data],
// Limpiar columna Descripcion que viene con HTML
Limpio = Table.AddColumn(
Lista,
"Descripcion_texto",
each try
Text.Combine(
Html.Table([Descripcion], {{"t", ":root"}})[t],
" "
)
otherwise null,
type text
),
// Opcional: eliminar la columna original con HTML
Final = Table.RemoveColumns(Limpio, {"Descripcion"})
in
Final
Cómo verificar que el texto quedó limpio
Después del paso de limpieza, añadí una columna de control:
= Table.AddColumn(
Limpio,
"Tiene HTML residual",
each Text.Contains([Descripcion_texto] ?? "", "<"),
type logical
)
Si alguna fila devuelve true, el HTML no se limpió completamente y necesitás revisar el caso.
Relación con HTML Content en Power BI
Si tu objetivo no es limpiar datos sino mostrar HTML como parte de un visual interactivo dentro del reporte, la herramienta correcta es el visual HTML Content de Power BI. Podés combinarlo con DAX para crear tarjetas con estilo, KPIs con iconos y semáforos de color. Mirá cómo construirlos en el artículo Creando cards visuales animados en Power BI con HTML Content.
Comparativa de métodos
| Método | HTML complejo | Entidades ( ) |
Múltiples párrafos | Recomendado para |
|---|---|---|---|---|
Html.Table + :root |
✅ | ✅ | Con Text.Combine |
Cualquier fuente real |
Text.Replace |
❌ (parcial) | ❌ | ❌ | HTML muy simple y predecible |
| Función reutilizable | ✅ | ✅ | ✅ | Múltiples columnas HTML |
El Método 1 con try...otherwise null es el que vas a querer tener guardado como snippet para la próxima vez que llegue una fuente con HTML.

Deja una respuesta