cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Check out the JMP® Marketplace featured Capability Explorer add-in
Choose Language Hide Translation Bar
Navigating your reports using XPath

*Pulling specific information from your reports can be challenging. For a lot of us, we learned to navigate our JMP reports using a subscripting method to access the values we wanted. The Tree Structure window was our friend (and still is) to show us all the display boxes that make up the report. 

You might have started out using the numbers shown in parentheses beside the display box names to make sure you had the right one. And then your colleague, who had different preferences or a different version of JMP, ran your script but didn't get the same results as you. 

Report( ow )[Number Col Box( 8 )][1];

It was puzzling, but soon you learned a more robust approach using relative referencing. That is, you navigated the report by subscripting using the title of the OutlineBox that contained the desired information.

Report( ow )[Outline Box( "Summary of Fit" )][Number Col Box( 1 )][1];

Wait, there’s another way to traverse JMP reports – and I think you are going to like it!

The following is an excerpt from Jump into JMP Scripting, Second Edition that discusses how you can apply the XPath query language to the XML representation of your JMP reports.  

XPath

Wait, there’s another way to traverse JMP reports!Wait, there’s another way to traverse JMP reports!Many of us are familiar with XML documents. For those who are not, XML stands for Extensible Markup Language. It is a markup language that establishes a set of rules for documents that are readable and understood by machines. XPath is a query language that enables you to navigate your XML documents.

Though XML looks quite a bit like HTML, their purposes are different. The purpose of HTML is to display content, whereas the purpose of XML is more about data storage and conveying content.

Let’s discuss a few of the primary components of an XML document:

  • Tags – Tags are what makes XML look a bit like HTML. Tags generally start with an opening less than sign (<) and end with a closing greater than sign (>). The tag name is specified between the < and > signs, and it is not a predefined value. Instead, the author of the document must establish the tag names. As in HTML, tags must be closed with a forward slash to represent an ending tag (for example, <tagname> content </tagname>).
  • Elements – An element consists of an entire tag statement, if you will. An element begins with the < of the opening tag all the way to and including the > of the closing tag. Elements can contain other elements, as well.
  • Attributes – Attributes are metadata or additional details about an element. An attribute is specified in the opening tag and can only have one value, specified in double quotation marks. A tag can have multiple attributes, but only one of each type.
  • Content – Content is the data. It is the text, numbers, and other characters between the opening and closing tags that make up an element.

Consider the following example XML file. The openTables element is the root element in which all other elements appear. The table element has an attribute called current, which has a value of 0 or 1. Inside each table element are three additional elements: name, numCols, and numRows. The data appears between the tags.

 

<openTables>

     <table current="1">
          <name>Big Class</name>
          <numCols>5</numCols>
          <numRows>40</numRows>
     </table>

     <table current="0">
          <name>Fitness</name>
          <numCols>9</numCols>
          <numRows>31<numRows>
     </table>

</openTables>

Now that we understand the structure of an XML document, we can apply that knowledge to the structure of a JMP report as an XML document. To see the XML representation of a JMP report, send the Get XML message to the report layer. The XML will appear in the log (View > Log).

 

     Chair1.png

 

Let’s look at an example. Suppose you wanted to programmatically determine how many Outline Boxes appeared in a Distribution report.

dt = Open( "$SAMPLE_DATA\Big Class.jmp" );

dist = dt << Distribution(
     Stack( 1 ),
     Continuous Distribution(
          Column( :height ),
          Horizontal Layout( 1 ),
          Vertical( 0 )
     )
);

You could use JSL to step through the display boxes and check their type, but it would be a rather tedious task. Instead, let’s look at the XML representation.

 

Write( Report( dist ) << Get XML );

The result shown in the log is a string that is nearly 180 lines long. Don’t be overwhelmed! Scroll to the top of the log and look at just the first tag:

 

/*:
<OutlineBox width="717" height="277" helpKey="Distrib" isOpen="true">

 

The tag is named OutlineBox and it has four attributes: width, height, helpKey, and isOpen. Everything that comes next is the content of the element, which is the title of the Outline Box and other elements. As you look at the other elements, notice that the element names are the same as the display box names in the tree structure but in an XML format.

Figure 7.5 XML Elements Compared to Tree Structure

<OutlineBox attributes>Title
  <ListBox attributes>
    <DropBox attributes>
      <SpacerBox attributes>
    </DropBox>
    <OutlineBox attributes>Title
    etc…
Figure 7.5.jpg

Now that we know the tag name of the element that we are searching for, let’s explore how we can use XPath to find out how many Outline Boxes there are.

     Chair2.png

In JMP, the XPath() message is sent to either the platform object or the report object. Its argument is an XPath expression used to retrieve information from the XML representation of the report. You do not have to use Get XML before you can use the XPath() message. But you might find it helpful to review the structure and available attributes.

The following will search the report for any Outline Boxes and return a list of references to each Outline Box.

obList = Report( dist ) << XPath( "//OutlineBox" );
Show( obList );
/*:
obList = {DisplayBox[OutlineBox], DisplayBox[OutlineBox], DisplayBox[OutlineBox],
DisplayBox[OutlineBox]};

We could simply use the NItems() function on obList to obtain the number of Outline Box references are stored in the list. Or as you learn more about the XPath language, you can use the XPath Count() function to return the count instead of a reference to each Outline Box.

obCount = N Items( Report( dist ) << XPath( "//OutlineBox" ) );
//OR
obCount = Report( dist ) << XPath( "count(//OutlineBox)" );

Now let’s look at a more interesting example. Suppose we wanted to display only the Mean and Std Dev columns in a Means and Std Deviations table of a Oneway report.

Figure 7.6 Oneway with Means and Std Deviations

Figure 7.6.jpg
dt = Open( 
"$SAMPLE_DATA\Big Class.jmp"
); ow = dt << Oneway( Y( :height ), X( :age ), Means and Std Dev( 1 ), Mean Error Bars( 1 ), Std Dev Lines( 1 ), Mean of Means( 1 ) );

We can return a list of just the Number Col Box references under the Means and Std Deviations table using
a combination of subscripting and XPath:

/* Return a list of NumberColBox references */
ncbList = Report( ow )["Means and Std Deviations"] << XPath( "//NumberColBox" );

Using a JSL For() loop, we can check the heading of the column and change the visibility property to
collapsed if the heading is anything other than Mean or Std Dev.

/* Loop through each item to show only the Mean, Std Dev columns */
For( i = 1, i <= N Items( ncbList ), i++,
	rptColName = ncbList[i] << Get Heading;
	If( !Contains( {"Mean", "Std Dev"}, rptColName ),
		ncbList[i] << Visibility( "Collapse" )
	);
);

But again, there is a way in XPath to accomplish the same result without the need for the For() loop. Look
at an excerpt of the XML representation of a Number Col Box from the report:

<NumberColBox leftOffset=\!"40\!" topOffset=\!"0\!" isVisible=\!"false\!">
<NumberColBoxHeader>Number</NumberColBoxHeader>

Notice that there is an element within the NumberColBox element called NumberColBoxHeader. This
element contains the report column heading. XPath enables us to capture that text and perform
comparisons. Only references to Number Col Boxes that have a heading that are anything other than Mean
or Std Dev are returned in a list.

colsToHide = Report( ow )["Means and Std Deviations"] << XPath(
    "//NumberColBox[NumberColBoxHeader[not(text() = 'Mean')
       and not(text() = 'Std Dev')]]"
);

This XPath query looks at NumberColBoxHeader elements that appear within a NumberColBox element. The Text function extracts the text from the NumberColBoxHeader element. In this example, if the text meets the criteria, meaning that the text is not mean and not Std Dev, then the reference is returned in a list.

Sending the Visibility() message to that list applies the setting to every item in the list.

colsToHide << Visibility( "Collapse" );

Figure 7.7 Oneway After Columns Are Hidden

Figure 7.7.jpg

Rosemary Lucas and I hope you have found these examples helpful for navigating your JMP reports. For more information about navigating your reports programmatically, check out Jump into JMP Scripting, Second Edition.

Cover_Missy.jpg

 

*Note: ClipArt Source: Blank Road Signs Clipart

Last Modified: Aug 7, 2019 2:51 PM
Comments
SpannerHead
Level IV

This is great information.  Is there a ready way to take something like <OutlineBox width="717" height="277" helpKey="Distrib" isOpen="true"> to generate a script to recreate an OutlineBox of this kind?

gail_massari
Community Manager

@Wendy_Murphrey  SpannerHead has a question.

jthi
Super User

What type of outline box are you talking about? You can create outline boxes using OutlineBox() and for example you can set red triangle options using << Set Menu Script.

Names Default To Here(1);
New Window("Example",
	fontobj = ob = Outline Box("Outline Box",
		V List Box(
			ob2 = Outline Box("Outline Box 2",
				H List Box(
					Text Edit Box("Top Left"),
					Text Edit Box("Top Right")
				)
			),
			ob3 = Outline Box("Outline Box 3",
				H List Box(
					Text Edit Box("Bottom Left"),
					Text Edit Box("Bottom Right")
				)
			)
		)
	)
);
ob << Set Menu Script(
	{"Beep", Beep(), "Beep Twice", Beep() ; Wait(1.0) ; Beep() ; ,
	"", 0, "Get Menu Script", Print(ob << Get Menu Script)}
);

If you just want to replicate that exact display box, you could use Clone Box and then remove all the child boxes. Doing something like this could potentially cause a lot of issues though

Names Default To Here(1); 

dt = open("$SAMPLE_DATA/Big Class.jmp");

dist = dt << Distribution(Nominal Distribution(Column(:sex)), Histograms Only);
obs = dist << XPath("//OutlineBox[@helpKey = 'Distrib']");
ob = obs[1];
obc = ob << Clone Box;
While(!IsEmpty(curchild = obc << child),
	curchild << delete box;
);

obc << get xml;