Merge pull request #362 from bhermanmit/xml-validation

XML Validation script
This commit is contained in:
Paul Romano 2015-02-20 08:27:04 -05:00
commit 47a6eecbf8
5 changed files with 175 additions and 9 deletions

View file

@ -51,6 +51,55 @@ files are called:
* ``plots.xml``
* ``cmfd.xml``
--------------------
Validating XML Files
--------------------
Input files can be checked before executing OpenMC using the ``xml_validate``
script. It is located in ``src/utils/xml_validate.py`` in the source code or in
``bin/xml_validate`` in the install directory. Before use, the third party
package TRANG_ must be installed and in your ``PATH`` to convert the compact
RelaxNG schema to standard RelaxNG format. For Ubuntu, you can install with:
.. code-block:: bash
sudo apt-get install trang
Two command line arguments can be set when running ``xml_validate``:
* ``-i``, ``--input-path`` - Location of OpenMC input files.
*Default*: current working directory
* ``-r``, ``--relaxng-path`` - Location of OpenMC RelaxNG files.
*Default*: None
If the RelaxNG path is not set, ``xml_validate`` will search for these files
because it expects that the user is either running the script located in the
install directory ``bin`` folder or in ``src/utils``. Once executed, it will
match OpenMC XML files with their RelaxNG schema and check if they are valid.
Below is a table of the messages that will be printed after each file is
checked.
======================== ===================================
Message Description
======================== ===================================
[XML ERROR] Cannot parse XML file.
[NO RELAXNG FOUND] No RelaxNG file found for XML file.
[TRANG FAILED] TRANG not installed properly.
[NOT VALID] XML file does not match RelaxNG.
[VALID] XML file matches RelaxNG.
======================== ===================================
As an example, if OpenMC is installed in the directory
``/opt/openmc/0.6.2`` and the current working directory is where
OpenMC XML input files are located, they can be validated using
the following command:
.. code-block:: bash
/opt/openmc/0.6.2/bin/xml_validate
.. _TRANG: http://www.thaiopensource.com/relaxng/trang.html
--------------------------------------
Settings Specification -- settings.xml
--------------------------------------

View file

@ -272,6 +272,10 @@ install(PROGRAMS utils/statepoint_meshplot.py
install(PROGRAMS utils/update_inputs.py
DESTINATION bin
RENAME update_inputs)
install(PROGRAMS utils/xml_validate.py
DESTINATION bin
RENAME xml_validate)
install(DIRECTORY relaxng DESTINATION share)
install(FILES ../man/man1/openmc.1 DESTINATION share/man/man1)
install(FILES ../LICENSE DESTINATION "share/doc/${program}/copyright")

View file

@ -904,7 +904,7 @@ contains
integer :: universe_num
integer :: n_cells_in_univ
integer :: coeffs_reqd
integer :: temp_int_array3(3)
integer :: temp_double_array3(3)
integer, allocatable :: temp_int_array(:)
real(8) :: phi, theta, psi
logical :: file_exists
@ -1052,10 +1052,10 @@ contains
end if
! Copy rotation angles in x,y,z directions
call get_node_array(node_cell, "rotation", temp_int_array3)
phi = -temp_int_array3(1) * PI/180.0_8
theta = -temp_int_array3(2) * PI/180.0_8
psi = -temp_int_array3(3) * PI/180.0_8
call get_node_array(node_cell, "rotation", temp_double_array3)
phi = -temp_double_array3(1) * PI/180.0_8
theta = -temp_double_array3(2) * PI/180.0_8
psi = -temp_double_array3(3) * PI/180.0_8
! Calculate rotation matrix based on angles given
allocate(c % rotation(3,3))

View file

@ -26,10 +26,8 @@ element tallies {
"surface" | "mesh" | "energy" | "energyout" ) } |
attribute type { ( "cell" | "cellborn" | "material" | "universe" |
"surface" | "mesh" | "energy" | "energyout" ) }) &
(element bins { list { xsd:string { maxLength = "20" }+ } } |
attribute bins { list { xsd:string { maxLength = "20" }+ } }) &
(element groups { xsd:string { maxLength = "20" }+ } |
attribute groups { xsd:string { maxLength = "20" }+ })?
(element bins { list { xsd:double+ } } |
attribute bins { list { xsd:double+ } })
}* &
element nuclides {
list { xsd:string { maxLength = "12" }+ }

115
src/utils/xml_validate.py Executable file
View file

@ -0,0 +1,115 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import sys
import glob
import lxml.etree as etree
from subprocess import call
from optparse import OptionParser
# Command line parsing
parser = OptionParser()
parser.add_option('-r', '--relaxng-path', dest='relaxng',
help="Path to RelaxNG files.")
parser.add_option('-i', '--input-path', dest='inputs', default=os.getcwd(),
help="Path to OpenMC input files." )
(options, args) = parser.parse_args()
# Colored output
if sys.stdout.isatty():
OK = '\033[92m'
FAIL = '\033[91m'
NOT_FOUND = '\033[93m'
ENDC = '\033[0m'
BOLD = '\033[1m'
else:
OK = ''
FAIL = ''
ENDC = ''
BOLD = ''
NOT_FOUND = ''
# Get absolute paths
if options.relaxng is not None:
relaxng_path = os.path.abspath(options.relaxng)
if options.inputs is not None:
inputs_path = os.path.abspath(options.inputs)
# Search for relaxng path if not set
if options.relaxng is None:
xml_validate_path = os.path.abspath(os.path.dirname(sys.argv[0]))
if "bin" in xml_validate_path:
relaxng_path = os.path.join(xml_validate_path, "..", "share", "relaxng")
elif os.path.join("src", "utils") in xml_validate_path:
relaxng_path = os.path.join(xml_validate_path, "..", "relaxng")
else:
raise Exception("Set RelaxNG path with -r command line option.")
if not os.path.exists(relaxng_path):
raise Exception("RelaxNG path: {0} does not exist, set with -r "
"command line option.".format(relaxng_path))
# Make sure there are .rnc files in RelaxNG path
rnc_files = glob.glob(os.path.join(relaxng_path, "*.rnc"))
if len(rnc_files) == 0:
raise Exception("No .rnc files found in RelaxNG "
"path: {0}.".format(relaxng_path))
# Get list of xml input files
xml_files = glob.glob(os.path.join(inputs_path, "*.xml"))
if len(xml_files) == 0:
raise Exception("No .xml files found at input path: {0}"
".".format(inputs_path))
# Begin loop around input files
for xml_file in xml_files:
text = "Validating {0}".format(os.path.basename(xml_file))
print(text + '.'*(30 - len(text)), end="")
# Validate the XML file
try:
xml_tree = etree.parse(xml_file)
except etree.XMLSyntaxError as e:
print(BOLD + FAIL + '[XML ERROR]' + ENDC)
print(" {0}".format(e))
continue
# Get xml_filename prefix
xml_prefix = os.path.basename(xml_file)
xml_prefix = xml_prefix.split(".")[0]
# Search for rnc file
rnc_file = os.path.join(relaxng_path, xml_prefix + ".rnc")
rng_file = xml_prefix + ".rng"
if rnc_file in rnc_files:
# convert RNC to RNG file
rc = call("trang {0} {1}".format(rnc_file, rng_file), shell=True)
# check return code
if rc == 0:
# read in RelaxNG
relaxng_doc = etree.parse(rng_file)
relaxng = etree.RelaxNG(relaxng_doc)
# validate xml file again RelaxNG
try:
relaxng.assertValid(xml_tree)
print(BOLD + OK + '[VALID]' + ENDC)
except (etree.DocumentInvalid, TypeError) as e:
print(BOLD + FAIL + '[NOT VALID]' + ENDC)
print(" {0}".format(e))
# remove rng file
os.remove(rng_file)
# trang command failed
else:
print(BOLD + FAIL + '[TRANG FAILED]' + ENDC)
# RNC file does not exist
else:
print(BOLD + NOT_FOUND + '[NO RELAXNG FOUND]' + ENDC)