cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Need to share some code when posting a question or reply? Make sure to use the "Insert code sample" menu option. Learn more! X

call Schematron from ACL menu item

AshleyHolmes
10-Marble

call Schematron from ACL menu item

We are using schematron for extra validation of our xml documents during the standard 'Check Completeness' function and working well.

 

We would like to create a separate menu item for a different schematron (a subset of <pattern>s) only to be run by certain users employees. We would like this second Schematron to be kicked off from a custom menu item using ACL.

 

I can create a menu no problem, but how can I get my menu item to reference the schematron file? Where should this schematron file be saved?

ACCEPTED SOLUTION

Accepted Solutions

Hi Ashley--

 

See the documentation for the ACL function "validate_against_schematron" in the Arbortext Help Center: https://support.ptc.com/cs/help/arbortext_hc/ae61_hc/index.jspx?id=help17197&action=show. This is the function you'll want to apply ad hoc schematron checks to a document.

 

--Clay

View solution in original post

30 REPLIES 30

Hi Ashley--

 

See the documentation for the ACL function "validate_against_schematron" in the Arbortext Help Center: https://support.ptc.com/cs/help/arbortext_hc/ae61_hc/index.jspx?id=help17197&action=show. This is the function you'll want to apply ad hoc schematron checks to a document.

 

--Clay

I am trying to implement this solution, and I have the function set up in my menu.acl

 

but it does not like the '0' arguement

 

function validate_against_schematron($S, 0, "cpha-editor.sch");

 

I get an error that says Unexpected Argument: 0,

 

I want the user to be able to open AE and then open the document, and run this schematron validation from a menu item, so 0 wont be set on initialization of AE, how can I work around this? what else can I put in instead of 0?

 

I would use something like this:

 

 

menu_add ".Tools." "Schematron Check" -cmd { validate_against_schematron($S, 0, "cpha-editor.sch"); }

Note that this will fill the $S array with any validation error messages, it will be up to you to display these to the user, or do something else with them.

 

If you just want to show the errors to the user, the easiest thing is probably to leverage the built-in "schematron" package code. There is a function defined there that does both the validation check and error message display, so maybe it's more direct to just use that. The function is called schematron::completeness_check_callback(doc, logname). So you could use something like this:

 

menu_add ".Tools." "Schematron Check" -cmd { schematron::completeness_check_callback(current_doc(), "Schematron Errors"); }

You may also need to make sure the schematron package is loaded before you can use this, so you can add a line near the top of your script file:

require schematron;

 

 

 

 

 

Thank you so much for breaking this down for me Clay!

I am getting somewhere.

 

I have the menu item appearing now with your second suggestion

It looks like this

 

if(!menu_exists(".$menu_name_condition.$menu_item_condition7")) {
menu_add .$menu_name_condition. "$menu_item_condition_show7" -cmd { schematron::completeness_check_callback(current_doc(), "Schematron Errors");}
}

 

and

require schematron;

at the top of my menu.acl file

I can now open AE without an errors.

 

I open a DITA document, run the new menu item, but I don't get any results from it. i.e. nothing comes up in an event log window that says "Schematron Errors" but the document I am using for sure has some.

 

Additionally, I do not want to run the overall schematron validation that we use for all our files (cpha-editor.sch) but instead I'd like to run another small schematron file that is checking for very specific things in particular documents.

 

This file is called drugTableValidation.sch, and it is stored in a different \doctype folder than the cpha-editor.sch schematron, which is the one that runs along with the usual Check Completeness schema validation.

 

 

We have a handful if schematron files like this, for these special use ones, I'd like to create ad hoc menu items to run them, and have that menu item NOT run the larger schematron validation we use for all the files.

 

 

 

OK, if you want to run specific schematron files, you'll probably have to go back to using validate_against_schematron(), and using calling the schematron logging function add_errors_to_log() to show the messages.

 

You can start by defining a function something like this:

function validate_schematron(schfile, log_name, doc=current_doc()) {
   local msgs[];
   validate_against_schematron(msgs, doc, schfile);
   schematron::add_errors_to_log(msgs, doc, log_name);
}

Then, your menu items can call this function with specific schematron files:

menu_add ".Tools." "Schematron 1" -cmd { validate_schematron("rules1.sch", "Schematron 1 Errors"); }
menu_add ".Tools." "Schematron 2" -cmd { validate_schematron("rules2.sch", "Schematron 2 Errors"); }
...etc...

Yesssss

Thank you Clay this is precisely what I am going for!

Almost there....

 

When i implement this, I get an error on AE initialization saying

Unrecognized function call: validate_against_schematron (msgs, doc, schfile)

 

validate_schematron is defined in the menu.acl file

but

Does the validate_against_schematron function have to be defined anywhere?

Do I need to make an .acl file for it in \scripts?

If so, what would I put in it?

 

 

Also, does it matter where drugTableValidation.sch is in the folder structure for the menu item to find it? Do I need to include a breadcrumb file path in the menu item for it or just the file name is sufficient?

 

 

Yes, that's what the line

require schematron;

is for. Make sure that appears at the top of any file that tries to call a schematron function and it should work.

 

This case is a little unusual, because validate_against_schematron() is defined in schematron.acl, but it is in the main::* package. If using "require schematron" doesn't fix the problem, try this instead:

autoload main::validate_against_schematron schematron

 

oops

when i put require schematron; back in, AE opens no problem

 

Also, menu item appears.

 

I click to run it, and nothing happens. I was expecting an event log window to pop up that says "Schematron 1 Errors".

In my menu item, i have

 

	if(!menu_exists(".$menu_name_condition.$menu_item_condition7")) { 
		menu_add .$menu_name_condition. "$menu_item_condition_show7" -cmd {validate_schematron("drugTableValidation.sch", "Schematron 1 Errors"); }
}

Do i need to put in a path for where my drugTableValidation.sch file is? or does it have to be in \scripts, or where should I put it? right now it is in \doctypes\[appropriate_subfolder]

 

Yes, you might need to include a path to the SCH file.

I keep trying but get no results coming up when I run the menu item.

I tried changing how the reference path is for the schematron but cannot get success.

 

I'm not sure if it cannot find the schematron file (this menu.acl file I am working in is on the server, and server has an E drive, and other menu items seem to point to other files on E drive this way seem to work. I've also tried with the actual server name in place of "E").

Or maybe the validate_schematron() function isn't executing?

 

This is my menu item in menu.acl

if(!menu_exists(".$menu_name_condition.$menu_item_condition7")) { 
   menu_add .$menu_name_condition. "$menu_item_condition_show7" -cmd {validate_schematron("E:\DITA_Custom\custom\doctypes\condition-relaxed\drugTableValidation.sch", "Schematron 1 Errors"); }
}

and this is my function in menu.acl

 

function validate_schematron(schfile, log_name, doc=current_doc()) {
   local msgs[];
   validate_against_schematron(msgs, doc, schfile);
   schematron::add_errors_to_log(msgs, doc, log_name);
}

I'm not sure how to tell which part is failing, or how I should be consuming the Error report - would an event log window pop up similiar to check completeness if the drugTableValidation file was executed?

 

 

OK, I do see one problem that might be causing issues: if you are going to use Windows-style path separators ("\"), you'll need to use single quotes rather than double quotes around the file path. Using double quotes causes the backslashes to be interpreted as escape characters. So, try changing the command in your menu_add statement  to this:

validate_schematron('E:\DITA_Custom\custom\doctypes\condition-relaxed\drugTableValidation.sch', "Schematron 1 Errors");

To figure out what part of the script might be failing you can use response() calls to pop up status at various points in the script. So, you could try something like this:

unction validate_schematron(schfile, log_name, doc=current_doc()) {
   response("validate_schematron is running");
   local msgs[];
   local result = validate_against_schematron(msgs, doc, schfile);
   response("validate_against_schematron is done, generated " . count(msgs) . " messages");
   schematron::add_errors_to_log(msgs, doc, log_name);
   response("validate_schematron is done, exiting script");
}

If everything is working right, you should get popup messages indicating the progress through the script.

 

Note that if there are no errors in your document (i.e. none of the schematron rules triggers a message), seeing nothing is the expected result. So, when you are testing, make sure your document has some conditions that will generate warnings.

Hi Clay,

 

The response() seems to work really well!! Thank you. Great suggestion. The only problem is it says generated 0 messages when I run it, when there should be 2 offenders. If it did pick up on the schematron infractions, where would I see details about - in an Event log pop up window?

 

I know this file has 2 infractions because when I put the same <pattern>s into my regular schematron validation file, and run it via check completeness, I get 2 schematron infractions coming out.

 

When I have these same <pattern>s in a separate drugTableValidation.sch file, and run it from the menu, it says in the response() pop up  "0 generated messages". They are the exact same <rule>s though. head scratch.

In that case, try adding the value of the "result" variable to the response() output. If the value is -1, then something went wrong with the schematron validation--either it couldn't read the schematron file, or there was some kind of validity issue with the contents of the schematron file.

I added

response(validate_against_schematron(msgs, doc, schfile));

and I am getting '0' as the response

so then

In my menu item, as a test, I changed the menu item to point to our overall schematron of cpha-editor.sch, and ran the menu item, and still received '0' even though I should have 2 violations, so I think the schematron is not being set and passed from the menu item to the validate_schematron function for some reason

This is how I have it right now

if(!menu_exists(".$menu_name_condition.$menu_item_condition7")) { 
	menu_add .$menu_name_condition. "$menu_item_condition_show7" -cmd {validate_schematron('E:\DITA_Custom\custom\doctypes\condition-relaxed\drugTableValidation.sch', "Schematron 1 Errors"); }
}
function validate_schematron(schfile, log_name, doc=current_doc()) {
   response("validate_schematron is running");
   local msgs[];
   local result = validate_against_schematron(msgs, doc, schfile);
   response(validate_against_schematron(msgs, doc, schfile));
   response("validate_against_schematron is done, generated " . count(msgs) . " messages");
   validate_against_schematron(msgs, doc, schfile);
   schematron::add_errors_to_log(msgs, doc, log_name);
   response("validate_schematron is done, exiting script");
}

I guess the next step is to add a line in your validate_schematron function to explicitly check for the schematron file, something like this:

function validate_schematron(schfile, log_name, doc=current_doc()) {
   response("validate_schematron is running");
   if (!access(schfile, "e")) {
      response("Couldn't find schematron file " . schfile);
   }
   local msgs[];
   local result = validate_against_schematron(msgs, doc, schfile);
   response("validate_against_schematron is done, generated " . count(msgs) . " messages");
   schematron::add_errors_to_log(msgs, doc, log_name);
   response("validate_schematron is done, exiting script");
}

That should tell you if it's having trouble interpreting the path of the schematron file.

that's it - thank you!

the function received the path from the menu item, but it cannot find the drugTableValidation schematron file.

the name comes up in the error message, so menu item is passing it to the function, but function cannot find it.

 

I've tried so many variations of the file path

double slashes, using the full path including the server name etc. I can't figure out why it cannot find the file

It should understand the same type of path that Windows understands. The easiest way to figure out the right path to use is to open the schematron file itself in Editor, and then use the Session Info panel to find the document path:

 

  1. From the menus choose Help->Session
  2. In the Session window, select the Document tab
  3. Read the location of the document from the first line in the table

If you use the same path you find there in your script, it should be able to read the file and apply it.

I got results!!!!

When I used the path as you suggested, my 2 infractions came up.

The issue was I was using E:\ which is the drive on the server, but my computer maps that server using the G drive. Other users may select different letters so I saved the schematron in a common folder on a drive everyone uses i.e. S:\ drive... S for "shared" and pointed the menu item there, and it WORKS.

 

 

Thank you Clay, so very  much, for all the help.

The schematron menu item solution is now up and running 😄

Glad to hear it! Persistence pays off.

I have one more task to sort out.

When I run the schematron from my menu item, some auto generated saxe error text comes up in the event log.

 

The rules in the Schematron have reports and assert tests with some custom text, and they should be outputting something like "The file ______________ is discontinued. Please revise your link"

 

The schematron is running, but I am not seeing my custom messages coming up anywhere. The function refers to "log_name", and add_errors_to_log - where can I find this log? Should it come up in a pop up window?

schematron::add_errors_to_log(msgs, doc, log_name);

If the messages window doesn't come up on its own, you may need to display it manually. Try adding this after your validation runs:

show_composer_log()

I tried adding

show_composer_log();

right after

 

   schematron::add_errors_to_log(msgs, doc, log_name);

but I didn't see any changes in the window pop ups.

You might need to initialize the event log to add new messages to it. Try adding this at the beginning of your function:

    _eventlog::end_job(log_name, 0, "warning");
    local log = _eventlog::start_job(log_name, "Schematron Errors");

Also, you may need to change your log name so it's a valid ID token, e.g. "schematron_log" or something like that.

Where all should I change it to be something semantic like schematron_log?


The configuration I have below doesnt seem to have any new window pop up with my custom schematron messages outlined in the .sch file.


Have I changed it in the appropriate places to see results? (I did try in the function params as well where it says log_name, but it didn't work)

 

function validate_schematron(schfile, log_name, doc=current_doc()) {
   _eventlog::end_job(Schematron_log, 0, "warning");
   local log = _eventlog::start_job(Schematron_log, "Schematron Errors");
   local msgs[];
   local result = validate_against_schematron(msgs, doc, schfile);
   validate_against_schematron(msgs, doc, schfile);
   response("validate_against_schematron is done, generated " . count(msgs) . " messages");
   schematron::add_errors_to_log(msgs, doc, Schematron_log);
   show_composer_log();
}

Where you have "Schematron_log" in your function, replace it with "log_name".

 

Also, you may need to wrap the call to schematron::add_errors_to_log() in an execute() call to defer evaluation of some of the variables. So, it would look something like this:

function validate_schematron(schfile, log_name, doc=current_doc()) {
   _eventlog::end_job(log_name, 0, "warning");
   local log = _eventlog::start_job(log_name, "Schematron Errors");
   local msgs[];
   local result = validate_against_schematron(msgs, doc, schfile);
   validate_against_schematron(msgs, doc, schfile);
   response("validate_against_schematron is done, generated " . count(msgs) . " messages");
   execute("schematron::add_errors_to_log(msgs, doc, log_name)");
   show_composer_log();
}

That worked!!! Excellent Clay thank you!

 

So close.

One small snag - I have to run the menu item twice.

 

When I run the menu item the first time, t an Event Log window opens with SAXParse information, which is normal.

In order to see the results of drugTableValidation.sch, I have to leave the Event Log window open, and run the menu item again, and then a new window opens with the Schematron 1 Errors in it.

 

If I close the Event log, before running the menu item for the second time, nothing appears. Always have to leave the Event log window up in order to see the schematron results.

 

Is there any way I can

a) merge the errors into one Event Log window or

b) make the Schematron errors appear with only running the menu item once?

I'm not sure why it's doing that. You could try adding a call to _eventlog::end_job() at the end of your function to see if that makes the messages appear the first time you call the function:

function validate_schematron(schfile, log_name, doc=current_doc()) {
   _eventlog::end_job(log_name, 0, "warning");
   local log = _eventlog::start_job(log_name, "Schematron Errors");
   local msgs[];
   local result = validate_against_schematron(msgs, doc, schfile);
   validate_against_schematron(msgs, doc, schfile);
   response("validate_against_schematron is done, generated " . count(msgs) . " messages");
   execute("schematron::add_errors_to_log(msgs, doc, log_name)");
_eventlog::end_job(log_name, 1); show_composer_log(); }

 In general, parser messages appear in a different window than completeness check messages (which is basically what we're generating here).

That did it!

 

Solution COMPLETE.

 

Thanks so much for your guidance Clay. I will be making more menu items for each of our individual schematrons now that this one is functioning as expected.

Announcements

Top Tags