Redgate Hub

  • Acceso a datos XML en PowerShell
    • Acceso a XML con XPath.
    • Acceso a XML como objetos.
    • Comparación de los enfoques XPath y de objetos
  • Modificación o creación de datos XML
    • Agregación de datos XML
    • Uso de XML para la serialización de objetos

Introducción

Como en cualquier lenguaje de alto nivel, the dataestá en el corazón de PowerShell. En el caso de PowerShell, esto se reduce a la conversión de datos externos en objetos de PowerShell y viceversa. Este es el segundo de una serie de artículos que muestra cómo importar casi todos los formatos de datos comunes que es probable que encuentres, y cómo exportar a algunos de ellos también. El primer artículo de la serie, PowerShell Data Basics: File-Based Data, cubre una variedad de formatos de texto, desde archivos de ancho fijo, ancho variable, y derecho de trazos hasta CSV, listas de propiedades, archivos INI, y datos JSON, y concluye con un tratamiento de la importación y exportación a Excel. Aquí nos concentramos en sacar el máximo provecho de XML.

Acceso a datos XML en PowerShell

Hay dos técnicas incorporadas para trabajar con datos XML en PowerShell; el enfoque XPath y el enfoque de anotación de puntos de objetos. Describiremos y compararemos estos dos enfoques, y los probaremos con algunos ejemplos de XML. Por comodidad, todos los ejemplos de código utilizan este archivo XML de muestra de MSDN. La figura 1 muestra una representación del esquema subyacente al archivo en un formato conciso (sobre todo si se compara con la lectura del archivo XSD en bruto), por cortesía del explorador de esquemas XML de Visual Studio. En la figura se observa que el archivo XML es un catálogo que contiene una colección de libros. Cada libro tiene siete características, seis de las cuales son elementos hijos y una que es un atributo hijo.

Figura 1 Esquema para el archivo XML de muestra de Microsofto:p>

Para cargar este archivo XML de muestra, puede utilizar cualquiera de estos:

si prefiere experimentar con datos XML inmediatos en lugar de cargar un archivo XML en un XmlDocument, es sencillo de hacer. Simplemente defina su XML como una cadena y castéelo a tipo XML como acabamos de hacer con el cmdlet Get-Content para archivos. Aquí está una porción del archivo XML de muestra con sólo dos libros:

Acceso a XML con XPath

Con el archivo cargado en un objeto XmlDocument, puede entonces navegar por el árbol XML con XPath. Para seleccionar un conjunto de nodos utilice el método SelectNodes:

$xdoc.SelectNodes(«//author»)

#text

Gambardella, Matthew

Ralls, Kim

Corets, Eva

Corets, Eva

Corets, Eva

Randall, Cynthia

Thurman, Paula

Knorr, Stefan

Kress, Peter

O’Brien, Tim

O’Brien, Tim

Galos, Mike

O utilice SelectSingleNode para devolver sólo un nodo:

$xdoc.SelectSingleNode(«//libro»)

id : bk102

autor : Ralls, Kim

título : Lluvia de medianoche

género : Fantasía

precio : 5,95

fecha_de_publicación : 2000-12-16

descripción : Una antigua arquitecta lucha contra zombis corporativos,

una malvada hechicera, y su propia infancia para convertirse en reina

del mundo.

Nota en el primer ejemplo que hay duplicados. Suponga en cambio que quiere una lista de autores únicos en el catálogo. Podría pensar que algo como …

1
$xdoc.SelectNodes(«//author») | select -Unique

…funcionaría, pero en realidad sólo devuelve el nombre del primer autor. Para entender por qué ha fallado, tendría que entender más sobre la estructura de los documentos XML. El primer ejemplo devuelve en realidad una lista de nodos de texto (es decir, no una lista de texto) y el filtro único está operando en esa lista, buscando la unicidad del tipo de elemento. Dado que todos los elementos de la colección son nodos de texto y, por tanto, todos tienen el mismo tipo de elemento, todos los nodos más allá del primero se consideran duplicados. El resultado es que sólo se devuelve el primero.

Lo que realmente se busca es el valor de la cadena de cada nodo autor. Desde el nodo autor debe acceder primero a su nodo texto (su primer y único hijo), y luego al valor de ese nodo texto (línea A en el siguiente ejemplo). Alternativamente, puede utilizar una expresión ligeramente más corta con la propiedad InnerText (línea B). Una variación más utiliza el cmdlet Select-Xml que evita una llamada a un método y por lo tanto es, en cierto sentido, un enfoque más distintivo de PowerShell (línea C). Las tres líneas devuelven el mismo resultado.

SelectNodes y SelectSingleNode juntos le dan una funcionalidad equivalente a Select-Xml. Ambos soportan espacios de nombres, que aún no he mencionado. Los dos métodos toman un XmlNamespaceManager como segundo parámetro opcional, mientras que el cmdlet Select-Xml toma un parámetro opcional Namespace que especifica sus espacios de nombres en una tabla hash.

SelectSingleNode devuelve un XmlNode y SelectNodes devuelve un XmlNodeList. Select-Xml, por otro lado, devuelve un objeto SelectXmlInfo (o una matriz de ellos) y su propiedad Node proporciona acceso al nodo subyacente. El ejemplo anterior ilustra estas diferencias.

Acceso a XML como objetos

Con el mismo objeto XmlDocument de la última sección, PowerShell también proporciona soporte de objetos dinámicos para datos XML: Esto le permite acceder a los datos XML como objetos PowerShell de primera clase, sin necesidad de un selector XPath ni de familiarizarse con los detalles de cosas como nodos XML, valores o nodos de texto. Además, ¡obtendrá Intellisense instantáneo y dinámico de su esquema XML cuando cargue sus datos XML! La Figura 2 ilustra esto para el ISE de PowerShell, donde obtienes tanto opciones de selección como completado de palabras, al igual que con los tokens nativos de PowerShell. Fíjate especialmente en la expansión inferior que busca lo que has escrito en cualquier parte del nombre de la propiedad, no sólo a partir del primer carácter: Intellisense encontraría aquí una propiedad de fecha tanto si se llama published_date como releaseDate o date_of_publication. Tenga en cuenta que tiene disponible el completamiento de palabras en PowerShell V2 o V3, y en PowerShell ISE o en la consola de PowerShell. Pero las opciones de selección sólo están disponibles en PowerShell ISE en V3.

Figura 2 Intellisense automático al cargar un documento XML

He aquí algunos ejemplos para mostrar que el XML se autoconvierte efectivamente en objetos PowerShell:

$xdoc

xml catalog

– —

version=»1.0″ catálogo

$xdoc.catálogo

libro

{libro, libro, libro, libro…}

$xdoc.catalog.book | Format-Table -AutoSize

id autor título género precio fecha_publicación descripción

– — — — —- —-

bk101 Gambardella, Matthew XML Developer’s Guide Computer 44.95 2000-10-01 Una mirada en profundidad a …

bk102 Ralls, Kim Midnight Rain Fantasy 5.95 2000-12-16 Una antigua arquitecta …

bk103 Corets, Eva Maeve Ascendant Fantasy 5.95 2000-11-17 Tras el colapso …

bk104 Corets, Eva Oberon’s Legacy Fantasy 5.95 2001-03-10 En el postapocalipsis…

bk105 Corets, Eva The Sundered Grail Fantasía 5.95 2001-09-10 Las dos hijas…

bk106 Randall, Cynthia Lover Birds Romance 4.95 2000-09-02 Cuando Carla conoce a …

bk107 Thurman, Paula Splish Splash Romance 4.95 2000-11-02 Un buceador de aguas profundas …

bk108 Knorr, Stefan Creepy Crawlies Horror 4.95 2000-12-06 Una antología de h…

bk109 Kress, Peter Paradox Lost Science Fiction 6.95 2000-11-02 Después de un inadvertido…

bk110 O’Brien, Tim Microsoft .NET: The Prog… Computer 36.95 2000-12-09 Microsoft’s .NET …

bk111 O’Brien, Tim MSXML3: A Comprehensive … Computer 36.95 2000-12-01 The Microsoft MSX…

bk112 Galos, Mike Visual Studio 7: A Compr… Computer 49.95 2001-04-16 Microsoft Visual …

$xdoc.catalog.book

id : bk103

autor : Corets, Eva

título : Maeve Ascendant

género : Fantasía

precio : 5,95

fecha_de_publicación : 2000-11-17

descripción : Tras el colapso de una sociedad nanotecnológica

en Inglaterra, los jóvenes supervivientes sientan las

fundaciones de una nueva sociedad

$xdoc.catalog.book.author

Randall, Cynthia

$xdoc.catalog.book.id

bk106

Observe que todos los nodos XML del documento se convierten en propiedades estándar de PowerShell, tanto si un nodo tiene hijos (por ejemplo, catálogo) como si es un nodo hoja (por ejemplo, precio), o si un nodo hoja es un elemento (por ejemplo, autor) o un atributo (por ejemplo, id). En particular (como ilustran los dos últimos ejemplos), los valores de los elementos y los de los atributos se tratan exactamente igual con la notación estándar de «puntos».

Comparación de los enfoques XPath y Object

¿Qué enfoque es mejor para acceder a los datos XML? La tabla 1 le ayuda a responder a esta pregunta. El enfoque de objetos suele ser más conciso (por ejemplo, la línea 3), pero no siempre (línea 4). XPath, sin embargo, es más expresivo, ya que permite especificar algunos selectores que no son posibles con la notación de objetos (línea 7). Sin embargo, las propias capacidades de PowerShell pueden llenar fácilmente este vacío cuando se utiliza la notación de objetos (línea 8).

Tabla 1 Comparación de los enfoques de XPath y de los selectores de objetos para el acceso a XML.

Modificación o creación de datos XML

Dada una apreciación de los selectores XML de las secciones anteriores, la modificación de un documento XML es bastante sencilla porque los selectores XML (ya sea XPath o de objetos) son valores L, es decir, ¡se puede escribir en ellos, así como leer de ellos! Así, cualquiera de estos modificará el autor del sexto libro:

1
2

$xdoc.SelectSingleNode(«//libro/autor»).InnerText = ‘jones’
$xdoc.catalog.book.author = ‘smith’

Muy a menudo, usted podría tener un archivo XML existente en el que desea cambiar uno o valores de nodo. Probablemente querrá leer el archivo, modificar los datos y volver a guardar el archivo con el mismo nombre. Has visto los dos primeros pasos; el tercer paso se hace con el método Save en el XmlDocument. Poniendo todo esto junto, entonces, se obtiene este código básico:

Este código se ejecuta bien – ¡excepto que la mayoría de las veces parecerá que ha fallado! Este simple trozo de código ilustra una noción de PowerShell aparentemente menor pero importante; la ignorancia de esto ha llevado a muchas publicaciones de blog que afirman que es un error en PowerShell. El problema es que el directorio de trabajo y la ubicación de PowerShell no son la misma cosa. El código anterior lee el archivo muy bien, modifica los datos muy bien, pero no necesariamente guarda el nuevo archivo donde se espera. Get-Content, al ser un cmdlet de PowerShell, ve una ruta de archivo relativa a la ubicación de PowerShell. El método XmlDocument.Save, por otro lado, ve una ruta de archivo relativa al directorio de trabajo del proceso PowerShell porque esa llamada al método está fuera de PowerShell. Si no ha ejecutado Set-Location (o su alias cd) en su sesión actual de PowerShell, ambos apuntan al mismo directorio. Para confirmarlo, ejecute estas dos sentencias:

1
2

Get-Location # muestra la ubicación de PowerShell
::CurrentDirectory # muestra el directorio de trabajo

El enfoque más seguro, entonces, es utilizar rutas absolutas para evitar este problema por completo. Ver el artículo de Alex Angelopoulos Por qué el directorio de trabajo de PowerShell y la ubicación de PowerShell no son uno en el mismo para más.

Añadir datos XML

Añadir nuevos nodos a su documento XML lleva un poco más de trabajo que modificar el valor de un nodo existente. Un enfoque que me gusta es el de la entrada del blog de Tobias Weltner Write, Add and Change XML Data: tome un nodo existente del tipo que desea crear, haga una copia de ese nodo y modifique la copia con sus nuevos datos, y finalmente inserte el nodo copiado en su XML como un hermano del original. Aplicando esto a nuestro ejemplo de catálogo de libros, este trozo de código crea un nuevo nodo de libro y lo añade al final de la colección:

Si desea añadir el nuevo libro en una ubicación diferente, por ejemplo después del tercer libro, utilice InsertAfter en lugar de AppendChild:

1
$xdoc.catalog.InsertAfter($libro,$xdoc.catalog.libro)

(El nombre del método InsertAfter desmiente el hecho de que no sólo añade nodos; ¡también puede mover nodos! El método comprueba si el nodo que se pide añadir ya está en el documento. Si es así, lo mueve a la nueva ubicación que usted especifique. Por lo tanto, cuando quiera copiar nodos, debe comenzar con el método Clone, como se ilustra más arriba.)

Para profundizar en la manipulación de datos XML con métodos .NET, consulte Procesar datos XML utilizando el modelo DOM en MSDN.

Usar XML para la serialización de objetos

PowerShell proporciona una forma sencilla de persistir objetos utilizando Export-Clixml para serializar cualquier objeto y almacenarlo en un archivo XML e Import-Clixml para restaurar el objeto desde XML. Con XML, a diferencia de la mayoría de las otras técnicas de serialización, se preserva la integridad del objeto: al restaurar un objeto desde XML, todas las propiedades están correctamente tipadas, al igual que el propio objeto padre, por lo que todos los métodos del objeto original están disponibles también en el objeto regenerado. Para utilizar Export-Clixml, basta con canalizarle cualquier colección de objetos y especificar un archivo de destino. Este es un ejemplo sencillo que muestra que la salida de Get-ChildItem, una colección de objetos FileSystemInfo, se regenera:

Deja una respuesta

Tu dirección de correo electrónico no será publicada.