¡Hola, chicos del scripting!Persecución de coches... y XML

Los chicos del scripting de Microsoft

Descargar el código de este artículo: HeyScriptingGuy2007_02.exe (150KB)

"NO SÉ por qué mi perro persigue a los coches", dice un viejo chiste. "A fin de cuentas, ¿qué haría con uno si consiguiera cogerlo?

Una buena pregunta, que los chicos del scripting no pueden contestar. Bueno, a menos que se trate de Lucy, el perro que corre calle abajo y que atrapa el coche. No tenemos ninguna duda de que ese perro robaría una tienda de licores y utilizaría el coche para escapar. Y teniendo en cuenta el estado del césped delantero, estamos dispuestos a apostar que no haría ninguna parada de descanso durante el camino, no sé si sabe a qué me refiero.

Si tuviéramos que actualizar esta antigua historia por una de la era de alta tecnología actual, quizás dé como resultado algo como esto: "No sé por qué mi Administrador de sistemas siguen intentando aprender XML. A fin de cuentas, ¿qué haría con él si consiguiera aprender?

Nota En nuestra defensa, sólo dijimos que íbamos a actualizar ese viejo chiste: nunca dijimos que iba a ser divertido.

Para ser sincero, puede que el XML sea una especie de tecnología sobrevalorada, al menos en lo referente a la administración del sistema. La verdad es que muchos administradores de sistemas han vivido mucho tiempo y han disfrutado unas vidas felices sin escribir jamás una secuencia de comandos que interactúe con un archivo XML, así que no esperamos que eso cambie en un futuro próximo.

Dicho esto, también es verdad que cada vez más aplicaciones adoptan el XML como estándar para el almacenamiento de datos. ¿Por qué no? Puesto que se trata de simples archivos de texto con adornos, estos archivos de datos XML son rápidos y fáciles de crear, son portátiles entre las plataformas y no requieren ningún complicado programa de base de datos (por no decir caro). ¿Tiene un sistema operativo y un editor de texto? Entonces puede crear una base de datos XML.

Lo que quiere decir, por supuesto, que existe al menos una cosa que un Administrador de sistemas puede hacer con XML: escribir secuencias de comandos que consulten un archivo XML como si ese archivo fuera una base de datos completa. ¿Y, oye, quién mejor que los chicos del scripting para darle unos cuantos consejos sobre cómo llevar esto a cabo?

Bueno, de acuerdo, buen tanto. Sin embargo, si tuviéramos que aventurarnos a hacer una suposición, apostaríamos a que Lucy está, probablemente, muy ocupada desenterrando el parterre de alguien como para escribir una columna acerca de XML.

Para empezar, echemos un vistazo a un archivo XML sencillo (consulte la Figura 1), un archivo de la base de datos que representa cuatro secuencias de comandos que se encuentran en la columna diaria ¡Hola, chicos del scripting!

Figure 1 ¡Hola, chicos del scripting! Secuencias de comandos en XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<Repository>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Print a Microsoft Access Report?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1020.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Compact a Microsoft Access Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1009.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Word</Subcategory>
    <Keyword>hyperlinks</Keyword>
    <Title>How Can I Change an Existing Hyperlink in a Microsoft Word Document?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
  <Script>
    <Category>Enterprise Servers</Category>
    <Subcategory>Microsoft SQL Server</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Create a Table in a SQL Server Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
</Repository>

Como puede ver, es un archivo pequeño, bastante sencillo. Cada secuencia de comandos individual se archiva bajo una etiqueta <Script>. De ahora en adelante, nos referiremos a estas secuencias de comandos como registros. Sí, tiene razón —los aficionados a XML nunca se referirían a estos elementos como registros. No importa: nuestro objetivo es mostrarle cómo aplicar algo que ya conoce —técnicas de consulta a la base de datos— a una clase nueva y diferente de origen de datos. Hemos pensado en centrarnos primero en cómo conseguir hacer las cosas, así que quizá volvamos a este tema en un futuro y le facilitemos la terminología apropiada.

De acuerdo, volvamos a los registros. Cada registro contiene los campos siguientes: <Category>, <Subcategory>, <Keyword>, <Title> y <URL>.

Hmm, parece que no está tan impresionado como cabía esperar. Quizá le ayudaría que le mostremos una secuencia de comandos que abriera este archivo XML y devolviera un eco del contenido:

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Scripts.xml")

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

For Each objNode in colNodes
   Wscript.Echo objNode.Text
Next

Nota Tenga cuidado: estos nombres de etiqueta distinguen entre mayúsculas y minúsculas. Es "/Repository/Script", no "/repository/script", ni "/REPOSITORY/SCRIPT".

Efectivamente, tampoco es demasiado impresionante. Pero ésa es la cuestión: no es ni la mitad de difícil de lo que esperaba.

Como puede ver en el código, empezamos creando una instancia del objeto Microsoft.XMLDOM, el objeto COM utilizado para el trabajo con archivos XML. Después, hemos establecido la propiedad Async en False. Esto garantiza que todo el archivo se lea en la memoria antes de que se le devuelva el control a la secuencia de comandos. A continuación, utilizamos el método de carga para leer el archivo C:\Scripts\Scripts.xml:

xmlDoc.Load("C:\Scripts\Scripts.xml")

En cuanto se haya cargado el archivo en la memoria, podemos utilizar el método selectNodes para seleccionar los registros especificados de la base de datos:

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

Échele un vistazo más detenidamente al parámetro transferido a selectNodes. Según parece, representa la ruta de acceso dentro del archivo XML. Nuestro archivo XML tiene la estructura siguiente:

<Repository>
    <Script>
        <Category></Category>
        <Subcategory></Subcategory>
        <Keyword></Keyword>
        <Title></Title>
        <URL></URL>
    </Script>
</Repository>

¿Debería preocuparse? En una palabra: ¡sí! Al tratar con archivos XML, la estructura es muy importante. ¿Por ejemplo, cómo obtenemos las propiedades individuales de un registro? Muy sencillo: accedemos a la etiqueta <Repository> seguida por la etiqueta <Script>, seguidas por las etiquetas individuales de la propiedad. Y, ¿saben qué? Es la misma ruta de acceso que especificamos como parámetro para selectNodes. Simplemente seguimos esa ruta de acceso con /*, lo que significa "Selecciona todas las propiedades de estos registros". En otras palabras, nuestra recopilación devuelta consistirá en todas las propiedades de todos los registros de la base de datos, parecido a una consulta "Selecciona * de" del servicio Instrumental de administración de Windows® (WMI).

Nota Inténtelo con la secuencia de comandos de muestra y verá exactamente a qué nos referimos.

El resto de la secuencia de comandos es fácil; lo único que tenemos que hacer es configurar un bucle For Each para movernos a través de la recopilación y devolver un eco del valor de la propiedad Text de cada elemento y cada propiedad:

For Each objNode in colNodes
   Wscript.Echo objNode.Text
Next

Más fácil que perseguir coches.

Sin embargo, tiene razón: si lo único que queríamos era devolver un eco de todo el contenido del archivo, podríamos habernos saltado toda esa historia del XML y simplemente utilizar FileSystemObject. (Quizás habría sido un poquito más complicado, pero apenas un poco). Si nuestra intención era deslumbrarle y hacerle pensar "Vaya, tampoco es tan difícil manejar este XML", bueno, probablemente aún tengamos otra posibilidades de demostrarlo.

Veamos qué podemos hacer al respecto. En la primera secuencia de comandos, recuperamos todos los valores de propiedad de todos los registros. Está bien, pero supongamos que lo que de verdad queríamos recuperar es el título de la secuencia de comandos. ¿Podemos hacerlo? Pues, un segundo...

De acuerdo, según Lucy, lo único que tenemos que hacer es modificar nuestro comando selectNodes, agregando la propiedad de interés al final de la ruta de acceso. En otras palabras:

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/Title")

Según parece, la única razón por la que recuperamos todas las propiedades la primera vez es porque utilizamos el carácter comodín *. Ahora recuperamos sólo la propiedad Title. ¿Por qué? Porque es el único valor de propiedad que hemos pedido recuperar.

Nota Vaya, mira eso: XML le da exactamente lo que ha pedido. No te ofendas, Lucy, ¡pero creemos que el XML es el nuevo mejor amigo del hombre!

Y, claro, puede devolver más de una propiedad. Por ejemplo, este comando modificado devuelve los valores para las propiedades Title y URL:

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL)")

Es verdad, la sintaxis es un poco rara, pero una vez se acostumbre, no está tan mal. Para empezar, especificamos la parte principal de la ruta de acceso, como hicimos antes:

    /Repository/Script/

A continuación, agregamos un conjunto de paréntesis y, dentro de esos paréntesis, especificamos las propiedades que se van a devolver. (Tenga en cuenta que utilizamos un separador —el carácter | — para separar las propiedades individuales). En otras palabras:

    (Title | URL)

Como dijimos, puede que sea un poco simplón, pero funciona.

Y no, no está limitado a devolver solamente dos propiedades. Mientras siga agregando con separadores, puede devolver toda la información que desee su espíritu. Por ejemplo, el comando que sigue devuelve tres propiedades (Title, URL y Keyword):

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL |          Keyword)")

Muy interesante, ¿verdad?

Bueno, pensamos que era interesante. Sin duda, son un público exigente. Sin embargo, de nuevo, ha marcado un buen tanto: lo único que hemos hecho hasta ahora es recuperar información acerca de todos los registros de la base de datos. Sin embargo, no hay nada malo en eso. Con frecuencia, suele ser lo que usted desea hacer. Por otro lado, habrá también veces (muchas veces) en las que queramos recuperar información únicamente acerca de un subconjunto de dichos registros. Por ejemplo, puede que queramos devolver información sólo acerca de las secuencias de comandos que tienen una palabra clave igual a las bases de datos. Ya sabe, con una consulta semejante a esta:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]")

De nuevo, la sintaxis es un poco rara. Como nota positiva, sin embargo, la sintaxis es también fácil y sin complicaciones. Después que especificar la ruta de acceso principal colocamos nuestra cláusula "Where" (por ejemplo, donde X iguala a Y) entre corchetes, de este modo:

/Repository/Script [Keyword = ‘databases’]

Como probablemente ya habrá deducido, nuestra cláusula Where equivalente indica la secuencia de comandos "Devuelve sólo los elementos en los que el atributo Keyword sea igual a las bases de datos". Tenga en cuenta que las bases de datos se encierran entre comillas sencillas. No sólo es completamente correcto, sino que es bastante necesario. Si el término del filtro está entre comillas dobles, obtendrá un error de sintaxis cuando intente ejecutar la secuencia de comandos.

Nota ¿Por qué? Porque, recuerde, toda la cadena de consulta —"/Repository/Script [Keyword = ‘databases’]"— está entre comillas dobles.

Por supuesto, no está limitado a utilizar el signo igual (=) al filtrar los datos. Puede utilizar los signos mayor que (>) o menor que (<), así como los favoritos de todos, los signos menor que o igual a (<=) y mayor que o igual a (>=). También puede anular cualquiera de estos signos colocando un signo de admiración delante. Por ejemplo, este comando solicita todas las secuencias de comandos donde Keyword no es igual a las bases de datos (fíjese en el signo !=):

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword != ‘databases’]")

Espere un segundo: ¿Quien ha dicho "Claro, se puede establecer un filtro, pero apuesto a que no se puede establecer un filtro y especificar las propiedades que desea que se devuelvan"? Por supuesto que puede:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]/Title")

Si todo va bien, este comando devolverá sólo la propiedad Title de todas las secuencias de comandos que tengan las bases de datos de Keyword. Veamos si funciona:

    How Can I Print a Microsoft Access Report?
    How Can I Compact a Microsoft Access Database?
    How Can I Create a Table in a SQL Server     Database?

Veamos si podemos incluir otro comando más antes de que se acabe el día. Aunque estamos progresando, aún podríamos devolver más registros de los que queremos devolver en realidad. A fin de cuentas, nuestro comando anterior devuelve una mezcla de secuencias de comandos de Microsoft® Access® y Microsoft SQL Server™. (¿Por qué? Porque todas estas secuencias de comandos utilizan las bases de datos de Keyword.) ¿Qué pasaría si quisiéramos limitar los datos devueltos a las secuencias de comandos que tengan bases de datos para la palabra clave y que tengan Microsoft SQL Server como subcategoría? ¿Es posible filtrar con múltiples criterios?

Como si tuviera que preguntar:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’ and " & _
    "Subcategory = ‘Microsoft SQL Server’]")

es la misma sintaxis básica; acabamos de utilizar dos criterios separados (a saber, Keyword = databases' y Subcategory = 'Microsoft SQL Server') y ha conectado ambas con el operador AND.

Nota Sí, tiene razón: con este simple y pequeño archivo XML podríamos haber solicitado todas las secuencias de comandos cuya subcategoría fuera igual a Microsoft SQL Server. Pero eso no habría sido divertido y cualquier cosa menos educativo.

También puede utilizar cláusulas OR. Por ejemplo, supongamos que tenemos una gran cantidad de secuencias de comandos de Microsoft Office, incluidos los que tienen una subcategoría igual a Microsoft Excel®, Microsoft PowerPoint®, Microsoft Outlook®, etcétera. ¿Es posible restringir los datos devueltos únicamente a las secuencias de comandos de las subcategorías Microsoft Word o Microsoft Access? Claro que sí:

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Subcategory = ‘Microsoft Word’ " & _
    "or Subcategory = ‘Microsoft Access’]")

¿Mejor así? Efectivamente, quizás no se trate de la columna que cambió su vida para siempre; sin embargo, existen bastantes probabilidades de que, tarde o temprano, consultar un archivo XML de esta manera sea factible. Pero la decisión es suya: puede aprender algunas técnicas XML básicas o puede perseguir coches. Como quiera. (Si elige esto último y resulta que se encuentra con Lucy, el perro que va corriendo calle abajo, salúdela de parte de los chicos del Scripting. ¡Y dígale que ni se acerque al jardín!)

¡Hola, chicos del scripting! - Todos los días

Acaba de examinar con detenimiento la columna ¡Hola, chicos del scripting! de este mes y ha pensado que es el mejor material técnico que ha leído jamás. Quizás vaya aún más allá y diga que es la mayor obra maestra escrita hasta la fecha. Es más, se detiene ansioso delante de su buzón esperando el siguiente número de la Revista de TechNet, para poder seguir leyendo artículos como éste.

¿A qué diantres está esperando? ¿Quiere saber más acerca de Lucy, el perro del vecindario, o leer acerca de las últimas proezas del hijo del scripting? ¿Ha oído cómo ha ido la serie de juegos Turducken Bowl del año pasado? Esté al tanto de todos estos importantes asuntos leyendo las columnas ¡Hola, chicos del scripting! diarias —sí, hemos dicho "diarias". De lunes a viernes (menos las principales fiestas y las vacaciones de los chicos del scripting), podrá leer todo lo relacionado con el béisbol, el fútbol y el baloncesto de las ligas escolares y alguna que otra vez obtener un pronóstico meteorológico local. (Hay que reconocerlo: sólo es local si por "local" usted entiende Redmont, aunque, ¿quién no quiere saber cómo está el tiempo en Redmond?)

No sólo eso, en realidad también aprenderá todos los días algo nuevo acerca de la redacción de secuencias de comandos. Sí, en medio de todo este contenido fascinante se encuentra la auténtica información sobre la redacción de secuencias de comandos. En cada columna, los chicos del scripting contestan a preguntas verdaderas, enviadas por gente que consideran personas reales. Puede leer la columna diaria en microsoft.com/technet/scriptcenter/resources/qanda. También, puesto que ellos ya han contestado a centenares de preguntas, los archivos son bastante extensos y constituyen un gran origen de información sobre la redacción de secuencias de comandos (consulte micros­oft.com/technet/scriptcenter/resources/qanda/hsgarch.mspx).

¿Tiene alguna pregunta para los chicos del scripting? Tendrá una pequeña oportunidad de recibir una respuesta si envía su pregunta a scripter@microsoft.com. (Por contra, no tendrá dicha oportunidad si no la envía, así que, ¿qué tiene que perder? A diferencia de un billete de lotería, es gratis y sus probabilidades son ligeramente mayores).

Los chicos del scripting de Microsoft trabajan para (bueno, son empleados de) Microsoft. Cuando no juegan al béisbol, ni entrenan ni lo ven (u otras actividades varias), dirigen el TechNet Script Center. Visite la página web www.scriptingguys.com.

© 2008 Microsoft Corporation and CMP Media, LLC. Reservados todos los derechos; queda prohibida la reproducción parcial o total sin previa autorización.