Example 5-16: Validating XML document against an XPath Ruleset

CREATE OR REPLACE PACKAGE BODY xpath_rules AS

  FUNCTION idForRuleset(ruleset_name VARCHAR2) RETURN NUMBER IS
    theId NUMBER;
  BEGIN
    SELECT id
      INTO theId
      FROM ruleset
     WHERE name = ruleset_name;
     RETURN theId;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN RETURN NULL;
  END;

  PROCEDURE validate( doc           IN xmldom.DOMDocument,
                      ruleset_name  IN VARCHAR2,
                      valid        OUT BOOLEAN,
                      errors       OUT VARCHAR2
                    ) IS
    errcount  NUMBER := 0;
    rulesetId NUMBER := idForRuleSet(ruleset_name);
  BEGIN
    IF xmldom.isNull(doc) THEN
      valid  := FALSE;
      errors := 'Cannot validate. Document is null';
    ELSIF rulesetId IS NULL THEN
      valid  := FALSE;
      errors := 'Cannot validate. Ruleset '||ruleset_name||' does not exist.';
    ELSE
      -- Assume the doc is valid until proven otherwise
      valid := TRUE;
      -- (1) Loop over all the rules for the ruleset whose name is passed in
      FOR curRule IN (SELECT name, xpath_test
                        FROM rule
                       WHERE ruleset = rulesetId) LOOP
        -- (2) Call xpath.test on the current rule's expression
        IF NOT xpath.test(doc,curRule.xpath_test) THEN
          -- (3) Keep track of rules that fail by bumping error count
          errcount := errcount + 1;
          -- Mark the doc invalid
          valid := FALSE;
          -- Put 2nd through Nth error on a new line.
          IF errcount > 1 THEN
            errors := errors ||CHR(10);
          END IF;
          errors := errors || '('||errcount||') '||curRule.name;
        END IF;
      END LOOP;
    END IF;
  END;
END;