Parsing XML in XPRESS Rules Within Sun's Identity Manager

I've been doing a lot of work with Sun's Identity Manager lately, and have some things that might be of interest to other's so I'll try to post them here as time permits.

I think the coolest thing I've done so far is to build a library for parsing XML within XPRESS. It's actually fairly straightforward, but it took me long enough to get right that it seems like a good thing to share. I have 2 XPRESS rules:

transformXML
Takes 2 strings, xml and xsl, as input, and returns the transformed data.
validateXML
Takes 2 strings, xml and xsd, as input, and returns 1 true if the XML validates against the XSD, and returns false otherwise.

Both rules invoke Java to do the actual work, but for reasons I'll explain later, validateXML is a bit more complex than transformXML. The XML transformation is simply a matter of figuring out the proper incantation to invoke:

<Rule name='transformXML'>
  <RuleArgument name='xml'/>
  <RuleArgument name='xsl'/>
 
  <block>
    <defvar name="StringWriter">
      <new class="java.io.StringWriter"/>
    </defvar>
    <invoke name="transform">
      <invoke name="newTransformer">
        <invoke name="newInstance" class="javax.xml.transform.TransformerFactory"></invoke>
        <new class="javax.xml.transform.stream.StreamSource">
          <new class="java.io.StringReader">
            <ref>xsl</ref>
          </new>
        </new>
      </invoke>
      <new class="javax.xml.transform.stream.StreamSource">
        <new class="java.io.StringReader">
          <ref>xml</ref>
        </new>
      </new>
      <new class="javax.xml.transform.stream.StreamResult">
        <ref>StringWriter</ref>
      </new>
    </invoke>
 
    <invoke name="toString">
      <ref>StringWriter</ref>
    </invoke>
  </block>
</Rule>

That looks fairly complicated, but it is pretty much a straight translation from the Java to XPRESS invocations. Unfortunately, XML validation isn't quite as straightforward. If there is a way to do it without exception handling, which is not available in XPRESS, I don't know what that way is. So, the direct invocations similar to the code above will not work.

It would be possible to write a bit of simple Java code to wrap the exception handling in a nice set of return codes, deploy that code with the IDM deployment and then invoke that from XPRESS, but I was really hoping to avoid custom Java if possible. In this case, JavaScript comes to the rescue (man, I never thought I would say that):

<Rule name='validateXML'>
  <RuleArgument name='xsd'/>
  <RuleArgument name='xml'/>
 
  <cond>
    <and>
      <notnull>
        <ref>xsd</ref>
      </notnull>
      <notnull>
        <ref>xml</ref>
      </notnull>
    </and>
    <script>
      importPackage(Packages.javax.xml.validation);
      importPackage(Packages.java.io);
      importPackage(Packages.javax.xml.transform.stream);
 
      var xsd = env.get('xsd');
      var xml = env.get('xml');
 
      var schemaFactory = SchemaFactory.newInstance('http://www.w3.org/2001/XMLSchema');
      var schema = schemaFactory.newSchema(new StreamSource(new StringReader(xsd)));
 
      var validator = schema.newValidator();
 
      var result = 'true';
 
      try {
        validator.validate(new StreamSource(new StringReader(xml)));
      }
      catch(err) {
        result = 'false';
      }
 
      result;
    </script>
    <s>false</s>
  </cond>
</Rule>

I've attached a rule library containing both these rules that you should be able to import and use in your project.

Have Fun.

AttachmentSize
Configuration-xmlRuleLibrary.xml3.72 KB