Web Q&A

Who Called the Script?, Concatenating Binary Files, and More

Edited by Nancy Michell

Q Is there a way to determine from which part of an HTML document a script was called, by getting, say, the ID of an element?

Q Is there a way to determine from which part of an HTML document a script was called, by getting, say, the ID of an element?

A Yes, there is. Take a look at the example in Figure 1. There are two buttons, each of which have script code that calls into a function named MyFunction. Inside of MyFunction is event.srcElement, which retrieves the particular element that triggered the initial event. Once you have this, you can get the caller's ID.

A Yes, there is. Take a look at the example in Figure 1. There are two buttons, each of which have script code that calls into a function named MyFunction. Inside of MyFunction is event.srcElement, which retrieves the particular element that triggered the initial event. Once you have this, you can get the caller's ID.

Figure 1 Who Called the Script?

<html> <head> <script> function MyFunction() { alert( window.event.srcElement.id ); } </script> </head> <body> <button id="1" onclick="MyFunction();">Button with id 1</button> <button id="2" onclick="MyFunction();">Button with id 2</button> </body> </html>

Q I am writing a script which needs to concatenate binary files together into one file. What I need is essentially the same functionality as the MS-DOS® command "copy /b file1+file2 file3".

Q I am writing a script which needs to concatenate binary files together into one file. What I need is essentially the same functionality as the MS-DOS® command "copy /b file1+file2 file3".

The File System Object (FSO) doesn't seem to be much help. I happened to try it with MP3 files, but they got corrupted.

A The FSO model supports only text files, not binary files. System administrators and script writers most commonly use text files to store information because they can easily read and write to these files. So the FSO model doesn't include any objects, methods, or properties to work with these types of files. If you want to manipulate any type of binary file you would need to use byte arrays or pointers to a memory address. Although adding them to the FSO model is possible, it would add an unpleasant level of complexity.

A The FSO model supports only text files, not binary files. System administrators and script writers most commonly use text files to store information because they can easily read and write to these files. So the FSO model doesn't include any objects, methods, or properties to work with these types of files. If you want to manipulate any type of binary file you would need to use byte arrays or pointers to a memory address. Although adding them to the FSO model is possible, it would add an unpleasant level of complexity.

The sensible solution is to use the shell command:

WShell.Run "cmd /c copy /b file1+file2 file3"

That does exactly what you want, it does it from script, it's one line of code, and it's guaranteed to work.

Q Suppose I have some XML and somewhere deep inside there is a node "mynode" that I'm looking for. This node is in namespace abc. It could be declared many ways:

<root xmlns:myns="abc">...<myns:mynode/>...</root> <root xmlns="abc">...<mynode/>...</root> <root>...<parent xmlns:myns="abc"><myns:mynode/><parent/>...</root> <root>...<myns:mynode xmlns:myns="abc"/>...</root> <root>...<m:mynode xmlns:m="abc"/>...</root>

I don't know in advance where the namespace alias is defined or how it is going to be called. So if I have an IXMLDOMNode pointer to <root> and I want to find the node called "mynode" in namespace abc, how do I do that using the Document Object Model? I cannot use an XPath query such as //mynode, //myns:mynode, or //*:mynode.

Q Suppose I have some XML and somewhere deep inside there is a node "mynode" that I'm looking for. This node is in namespace abc. It could be declared many ways:

<root xmlns:myns="abc">...<myns:mynode/>...</root> <root xmlns="abc">...<mynode/>...</root> <root>...<parent xmlns:myns="abc"><myns:mynode/><parent/>...</root> <root>...<myns:mynode xmlns:myns="abc"/>...</root> <root>...<m:mynode xmlns:m="abc"/>...</root>

I don't know in advance where the namespace alias is defined or how it is going to be called. So if I have an IXMLDOMNode pointer to <root> and I want to find the node called "mynode" in namespace abc, how do I do that using the Document Object Model? I cannot use an XPath query such as //mynode, //myns:mynode, or //*:mynode.

A To perform the XPath query you need to know the namespace uri, not the prefix that represents it on the doc. Prefix aliases in the docs are not related to the ones you should use on the XPath except by the fact that they point to the same namespace. With MSXML 4.x, to specify prefixes used on an XPath you set the SelectionNamespaces property. This sample is taken directly from the MSXML 4.x documentation:

var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.4.0"); var objNodeList; xmlDoc.async = false; xmlDoc.load("hello.xsl"); xmlDoc.setProperty("SelectionNamespaces", "xmlns:xsl='https://www.w3.org/1999/XSL/Transform'"); xmlDoc.setProperty("SelectionLanguage", "XPath"); objNodeList = xmlDoc.documentElement.selectNodes("//xsl:template"); alert(objNodeList.length);

A To perform the XPath query you need to know the namespace uri, not the prefix that represents it on the doc. Prefix aliases in the docs are not related to the ones you should use on the XPath except by the fact that they point to the same namespace. With MSXML 4.x, to specify prefixes used on an XPath you set the SelectionNamespaces property. This sample is taken directly from the MSXML 4.x documentation:

var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.4.0"); var objNodeList; xmlDoc.async = false; xmlDoc.load("hello.xsl"); xmlDoc.setProperty("SelectionNamespaces", "xmlns:xsl='https://www.w3.org/1999/XSL/Transform'"); xmlDoc.setProperty("SelectionLanguage", "XPath"); objNodeList = xmlDoc.documentElement.selectNodes("//xsl:template"); alert(objNodeList.length);

Q In my XML, I have some HTML, but MSXML doesn't see HTML. So, when transforming XML via XSL, is there a way to grab an element's inner text as text rather than as XML?

Q In my XML, I have some HTML, but MSXML doesn't see HTML. So, when transforming XML via XSL, is there a way to grab an element's inner text as text rather than as XML?

A First, is your HTML making the XML not well formed? If so, then the transformation won't work unless you wrap the contents of the root in a CDATA section and use "disable-output-escaping='yes'":

<Root> <![CDATA[ <p>this is a <b>para</b></p><hr> ]]> </Root>

Then your XSL would be:

<xsl:template match="Root"> <xsl:value-of select="." disable-output-escaping="yes"/> </xsl:template>

If your XML is well formed, then simply use <xsl:output method="html"> and <xsl:copy-of> to output the HTML content as is and your result will be HTML.

<xsl:template match="Root"> <xsl:copy-of select="." /> </xsl:template>

A First, is your HTML making the XML not well formed? If so, then the transformation won't work unless you wrap the contents of the root in a CDATA section and use "disable-output-escaping='yes'":

<Root> <![CDATA[ <p>this is a <b>para</b></p><hr> ]]> </Root>

Then your XSL would be:

<xsl:template match="Root"> <xsl:value-of select="." disable-output-escaping="yes"/> </xsl:template>

If your XML is well formed, then simply use <xsl:output method="html"> and <xsl:copy-of> to output the HTML content as is and your result will be HTML.

<xsl:template match="Root"> <xsl:copy-of select="." /> </xsl:template>

However, if your XML looks like this

<Root> <![CDATA[ <p>this is a <b>para</b></p><hr> ]]> </Root>

and you have control over the format, you will have a better XSLT experience if you make the HTML XML-compliant:

<Root> <p>this is a <b>para</b></p><hr/> </Root>

Then you will have the ability to query on tags and content within your HTML and change the format easily.

Q How can I reference an external VBScript file from an existing VBScript file which will be run at the command prompt?

Q How can I reference an external VBScript file from an existing VBScript file which will be run at the command prompt?

A The best way is to write a Windows® Script Host File.

<job> <script language="VBScript" src="c:\library.vbs"/> <script language="VBScript"> ' whatever </script> </job>

A The best way is to write a Windows® Script Host File.

<job> <script language="VBScript" src="c:\library.vbs"/> <script language="VBScript"> ' whatever </script> </job>

You might wonder why there is no #include, like in C. That's because #include would have to mean something different in every host. In Microsoft® Internet Explorer you have to use the Internet Explorer security model to ensure that scripts aren't being included across domains and that they support URL paths. In ASP, you have to use vroot paths. In Windows Script Host you would use file system paths, and so on down the line. It gets too complicated.

Q I've been storing my department's user info (phone numbers, passwords, cubicle locations, and so on) in various Microsoft Excel spreadsheets, which have become difficult to keep current. I want to design a database with Microsoft Access 2000 to keep track of all the information and in turn match each user to a cubicle. The problem is that the employees get moved around a few times each year, and trying to remember who is where is not feasible. I want to use a floorplan as the UI for the database so I can click on a cubicle to bring up the associated record and edit it. I'd like to display the current user names as labels in the cubicles.

Q I've been storing my department's user info (phone numbers, passwords, cubicle locations, and so on) in various Microsoft Excel spreadsheets, which have become difficult to keep current. I want to design a database with Microsoft Access 2000 to keep track of all the information and in turn match each user to a cubicle. The problem is that the employees get moved around a few times each year, and trying to remember who is where is not feasible. I want to use a floorplan as the UI for the database so I can click on a cubicle to bring up the associated record and edit it. I'd like to display the current user names as labels in the cubicles.

Here's an example: Bob is in cubicle 1001A. When the database is opened, a floorplan with names is displayed, and I can click on Bob and see all his associated information (login, phone extension, and so forth). However, if Bob moves to cubicle 1234, all that should be necessary is to update the cubicle number, and the floorplan should change to reflect the new location (so now cubicle 1001A will show as empty). How can I do this?

A You could use a form with button controls. Set up the structure of the database, and in the relevant table (let's call it User Info) call the fields "Jack" for the phone jack and "User" for the employee. When you look up a phone jack in the table you want the label set to the value of the employee who has that number. Once the label is set properly, you can add a click event handler to open up another form for that record.

A You could use a form with button controls. Set up the structure of the database, and in the relevant table (let's call it User Info) call the fields "Jack" for the phone jack and "User" for the employee. When you look up a phone jack in the table you want the label set to the value of the employee who has that number. Once the label is set properly, you can add a click event handler to open up another form for that record.

All you need to do is to pull the field value and assign it to the button caption (see Figure 2). The Open event calls SetUserButtons with "Me" as the argument. The SetUserButtons code takes every control in the form, and if it's a command button, looks up the object's Name in the User_Info table (where it matches a field called Location). Then it sets the caption of the object to be the user name, his phone extension, and his cubicle location. The only other non-wizard code in there opens the appropriate form:

Private Sub Ctl1003a_Click() OpenSubForm "1003a" End Sub Sub OpenSubForm(button As String) Dim frm As String, rs As Recordset frm = "SelectItem" DoCmd.OpenForm frm, , , "Location = '" & button & "'" End Sub

Figure 2 Put User Name on Button

Private Sub Form_Open(Cancel As Integer) SetUserButtons Me End Sub Sub SetUserButtons(frm As Form) Dim rs As Recordset, ctl As Control For Each ctl In frm.Controls If ctl.ControlType = acCommandButton Then With ctl Set rs = CurrentDb.OpenRecordset("select * from user_info where location = '" & ctl.Name & "'") Do Until rs.EOF ctl.Caption = rs!User & " - #" & _ rs!Extension & " - " & rs!Location rs.MoveNext Loop End With End If Next ctl End Sub

Right now the button names are hardcoded into the click events. When clicked, the button passes the hardcoded string to the DoCmd.Openform command, which filters by location.

Everything else in the database is generic wizard code, including the searches. In this database, all the tables have relationships, so editing can be performed right in the form. The Search buttons aren't affected by the SetUserButtons code because the entire map and tab-buttons set is a subform within the form you see, and the open event is only triggered on the subform.

Obviously, you could port all of this to a Web page front end so you can access it from anywhere and let users make changes.

Figure 3 User by Cubicle

Figure 3** User by Cubicle **

You'll also need to add error handling, but otherwise you're all set. Figure 3 shows the application running in Access. The center of the figure shows the cubicles with their corresponding buttons.

Q I need a tool that compares two XML files. The tool should say the files are equal if they are identical except for different ordering of elements and attributes. Also, can I have different XML files in a single file, like a .chm file, which has multiple indexed .htm files?

Q I need a tool that compares two XML files. The tool should say the files are equal if they are identical except for different ordering of elements and attributes. Also, can I have different XML files in a single file, like a .chm file, which has multiple indexed .htm files?

A Try Microsoft XML Diff and Patch—a set of tools for comparing two XML documents. XML Diff detects additions, deletions, and other changes made between two XML documents. It also detects structural changes like the move of an XML subtree. Check it out at https://xmldiff.codeplex.com/.

A Try Microsoft XML Diff and Patch—a set of tools for comparing two XML documents. XML Diff detects additions, deletions, and other changes made between two XML documents. It also detects structural changes like the move of an XML subtree. Check it out at https://xmldiff.codeplex.com/.

You can have different XML files in one file as long as the complete XML is well formed, but it is inadvisable because the uniformity of the data is lost, the schema information becomes complex or makes no sense, and it becomes hard to maintain and transform. Also, if there are nodes with similar names they may clash in the queries unless you separate them with unique namespaces.

Got a question? Send questions and comments to  webqa@microsoft.com.

Thanks to the following Microsoft developers for their technical expertise: Earl Beaman, Jonas Brandel, Manuel Rebello de Andrade, Derek Denny-Brown, Michael Gibson, Lei Guy, Brian Heitt, Dion Houston, Dmitry Kakurin, Pranav Kandula, Michael Kaplan, Prashant Kudli, Krishna Kumar, Eric Lippert, Jonmichael Presley, Nate Sternberg, Bruce Taimana, Konrad Tupaj, Michael Whalen, Federico Winkel. Also, special thanks to reader Mike Young.