Search in sources :

Example 1 with PSRule

use of com.helger.schematron.pure.model.PSRule in project ph-schematron by phax.

the class PSPreprocessor method _resolveRuleContent.

/**
 * Resolve all <extends> elements. This method calls itself recursively
 * until all extends elements are resolved.
 *
 * @param aRuleContent
 *        A list consisting of {@link PSAssertReport} and {@link PSExtends}
 *        objects. Never <code>null</code>.
 * @param aLookup
 *        The rule lookup object
 * @throws SchematronPreprocessException
 *         If the base rule of an extends object could not be resolved.
 */
private void _resolveRuleContent(@Nonnull final ICommonsList<IPSElement> aRuleContent, @Nonnull final PreprocessorLookup aLookup, @Nonnull final PreprocessorIDPool aIDPool, @Nullable final ICommonsMap<String, String> aParamValueMap, @Nonnull final PSRule aTargetRule) throws SchematronPreprocessException {
    for (final IPSElement aElement : aRuleContent) {
        if (aElement instanceof PSAssertReport) {
            final PSAssertReport aAssertReport = (PSAssertReport) aElement;
            aTargetRule.addAssertReport(_getPreprocessedAssert(aAssertReport, aIDPool, aParamValueMap));
        } else {
            final PSExtends aExtends = (PSExtends) aElement;
            final String sRuleID = aExtends.getRule();
            final PSRule aBaseRule = aLookup.getAbstractRuleOfID(sRuleID);
            if (aBaseRule == null)
                throw new SchematronPreprocessException("Failed to resolve rule ID '" + sRuleID + "' in extends statement. Available rules are: " + aLookup.getAllAbstractRuleIDs());
            // Recursively resolve the extends of the base rule
            _resolveRuleContent(aBaseRule.getAllContentElements(), aLookup, aIDPool, aParamValueMap, aTargetRule);
            // Copy all lets
            for (final PSLet aBaseLet : aBaseRule.getAllLets()) aTargetRule.addLet(aBaseLet.getClone());
        }
    }
}
Also used : IPSElement(com.helger.schematron.pure.model.IPSElement) PSRule(com.helger.schematron.pure.model.PSRule) PSAssertReport(com.helger.schematron.pure.model.PSAssertReport) PSLet(com.helger.schematron.pure.model.PSLet) PSExtends(com.helger.schematron.pure.model.PSExtends)

Example 2 with PSRule

use of com.helger.schematron.pure.model.PSRule in project ph-schematron by phax.

the class PSPreprocessor method _getPreprocessedPattern.

@Nullable
private PSPattern _getPreprocessedPattern(@Nonnull final PSPattern aPattern, @Nonnull final PreprocessorLookup aLookup, @Nonnull final PreprocessorIDPool aIDPool) throws SchematronPreprocessException {
    if (aPattern.isAbstract()) {
        // Will be inlined
        return null;
    }
    final PSPattern ret = new PSPattern();
    // abstract always false
    // is-a must be resolved
    ret.setID(aIDPool.getUniqueID(aPattern.getID()));
    ret.setRich(aPattern.getRichClone());
    if (aPattern.hasAnyInclude())
        throw new SchematronPreprocessException("Cannot preprocess <pattern> with an <include>");
    if (m_bKeepTitles && aPattern.hasTitle())
        ret.setTitle(aPattern.getTitle().getClone());
    final String sIsA = aPattern.getIsA();
    if (sIsA != null) {
        final PSPattern aBasePattern = aLookup.getAbstractPatternOfID(sIsA);
        if (aBasePattern == null)
            throw new SchematronPreprocessException("Failed to resolve the pattern denoted by is-a='" + sIsA + "'");
        if (!ret.hasID())
            ret.setID(aIDPool.getUniqueID(aBasePattern.getID()));
        if (!ret.hasRich())
            ret.setRich(aBasePattern.getRichClone());
        // get the string replacements
        final ICommonsNavigableMap<String, String> aParamValueMap = m_aQueryBinding.getStringReplacementMap(aPattern.getAllParams());
        for (final IPSElement aElement : aBasePattern.getAllContentElements()) {
            if (aElement instanceof PSLet)
                ret.addLet(((PSLet) aElement).getClone());
            else if (aElement instanceof PSRule) {
                final PSRule aMinifiedRule = _getPreprocessedRule((PSRule) aElement, aLookup, aIDPool, aParamValueMap);
                if (aMinifiedRule != null)
                    ret.addRule(aMinifiedRule);
            }
        // params must have be resolved
        // ps are ignored
        }
    } else {
        for (final IPSElement aElement : aPattern.getAllContentElements()) {
            if (aElement instanceof PSLet)
                ret.addLet(((PSLet) aElement).getClone());
            else if (aElement instanceof PSRule) {
                final PSRule aMinifiedRule = _getPreprocessedRule((PSRule) aElement, aLookup, aIDPool, null);
                if (aMinifiedRule != null)
                    ret.addRule(aMinifiedRule);
            }
        // params must be resolved
        // ps are ignored
        }
    }
    ret.addForeignElements(aPattern.getAllForeignElements());
    ret.addForeignAttributes(aPattern.getAllForeignAttributes());
    return ret;
}
Also used : IPSElement(com.helger.schematron.pure.model.IPSElement) PSRule(com.helger.schematron.pure.model.PSRule) PSLet(com.helger.schematron.pure.model.PSLet) PSPattern(com.helger.schematron.pure.model.PSPattern) Nullable(javax.annotation.Nullable)

Example 3 with PSRule

use of com.helger.schematron.pure.model.PSRule in project ph-schematron by phax.

the class PSXPathBoundSchema method _createBoundPatterns.

/**
 * Pre-compile all patterns incl. their content
 *
 * @param aXPathContext
 * @param aXPathContext
 *        Global XPath object to use. May not be <code>null</code>.
 * @param aBoundDiagnostics
 *        A map from DiagnosticID to its mapped counterpart. May not be
 *        <code>null</code>.
 * @param aGlobalVariables
 *        The global Schematron-let variables. May not be <code>null</code>.
 * @return <code>null</code> if an XPath error is contained
 */
@Nullable
private ICommonsList<PSXPathBoundPattern> _createBoundPatterns(@Nonnull final XPath aXPathContext, @Nonnull final ICommonsMap<String, PSXPathBoundDiagnostic> aBoundDiagnostics, @Nonnull final IPSXPathVariables aGlobalVariables) {
    final ICommonsList<PSXPathBoundPattern> ret = new CommonsArrayList<>();
    boolean bHasAnyError = false;
    // For all relevant patterns
    for (final PSPattern aPattern : getAllRelevantPatterns()) {
        // Handle pattern specific variables
        final PSXPathVariables aPatternVariables = aGlobalVariables.getClone();
        if (aPattern.hasAnyLet()) {
            // map
            for (final Map.Entry<String, String> aEntry : aPattern.getAllLetsAsMap().entrySet()) if (aPatternVariables.add(aEntry).isUnchanged())
                error(aPattern, "Duplicate <let> with name '" + aEntry.getKey() + "' in <pattern>");
        }
        // For all rules of the current pattern
        final ICommonsList<PSXPathBoundRule> aBoundRules = new CommonsArrayList<>();
        for (final PSRule aRule : aPattern.getAllRules()) {
            // Handle rule specific variables
            final PSXPathVariables aRuleVariables = aPatternVariables.getClone();
            if (aRule.hasAnyLet()) {
                // variable map
                for (final Map.Entry<String, String> aEntry : aRule.getAllLetsAsMap().entrySet()) if (aRuleVariables.add(aEntry).isUnchanged())
                    error(aRule, "Duplicate <let> with name '" + aEntry.getKey() + "' in <rule>");
            }
            // For all contained assert and reports within the current rule
            final ICommonsList<PSXPathBoundAssertReport> aBoundAssertReports = new CommonsArrayList<>();
            for (final PSAssertReport aAssertReport : aRule.getAllAssertReports()) {
                final String sTest = aRuleVariables.getAppliedReplacement(aAssertReport.getTest());
                try {
                    final XPathExpression aTestExpr = _compileXPath(aXPathContext, sTest);
                    final ICommonsList<PSXPathBoundElement> aBoundElements = _createBoundElements(aAssertReport, aXPathContext, aRuleVariables);
                    if (aBoundElements == null) {
                        // Error already emitted
                        bHasAnyError = true;
                    } else {
                        final PSXPathBoundAssertReport aBoundAssertReport = new PSXPathBoundAssertReport(aAssertReport, sTest, aTestExpr, aBoundElements, aBoundDiagnostics);
                        aBoundAssertReports.add(aBoundAssertReport);
                    }
                } catch (final Throwable t) {
                    error(aAssertReport, "Failed to compile XPath expression in <" + (aAssertReport.isAssert() ? "assert" : "report") + ">: '" + sTest + "' with the following variables: " + aRuleVariables.getAll(), t);
                    bHasAnyError = true;
                }
            }
            // Evaluate base node set for this rule
            final String sRuleContext = aGlobalVariables.getAppliedReplacement(getValidationContext(aRule.getContext()));
            PSXPathBoundRule aBoundRule = null;
            try {
                final XPathExpression aRuleContext = _compileXPath(aXPathContext, sRuleContext);
                aBoundRule = new PSXPathBoundRule(aRule, sRuleContext, aRuleContext, aBoundAssertReports);
                aBoundRules.add(aBoundRule);
            } catch (final XPathExpressionException ex) {
                error(aRule, "Failed to compile XPath expression in <rule>: '" + sRuleContext + "'", ex.getCause() != null ? ex.getCause() : ex);
                bHasAnyError = true;
            }
        }
        // Create the bound pattern
        final PSXPathBoundPattern aBoundPattern = new PSXPathBoundPattern(aPattern, aBoundRules);
        ret.add(aBoundPattern);
    }
    if (bHasAnyError)
        return null;
    return ret;
}
Also used : XPathExpression(javax.xml.xpath.XPathExpression) PSRule(com.helger.schematron.pure.model.PSRule) XPathExpressionException(javax.xml.xpath.XPathExpressionException) PSXPathVariables(com.helger.schematron.pure.binding.xpath.PSXPathVariables) IPSXPathVariables(com.helger.schematron.pure.binding.xpath.IPSXPathVariables) PSAssertReport(com.helger.schematron.pure.model.PSAssertReport) PSPattern(com.helger.schematron.pure.model.PSPattern) Map(java.util.Map) CommonsHashMap(com.helger.commons.collection.impl.CommonsHashMap) ICommonsMap(com.helger.commons.collection.impl.ICommonsMap) CommonsArrayList(com.helger.commons.collection.impl.CommonsArrayList) Nullable(javax.annotation.Nullable)

Example 4 with PSRule

use of com.helger.schematron.pure.model.PSRule in project ph-schematron by phax.

the class PSPreprocessor method _getPreprocessedRule.

@Nullable
private PSRule _getPreprocessedRule(@Nonnull final PSRule aRule, @Nonnull final PreprocessorLookup aLookup, @Nonnull final PreprocessorIDPool aIDPool, @Nullable final ICommonsMap<String, String> aParamValueMap) throws SchematronPreprocessException {
    if (aRule.isAbstract()) {
        // Will be inlined
        return null;
    }
    final PSRule ret = new PSRule();
    ret.setFlag(aRule.getFlag());
    ret.setRich(aRule.getRichClone());
    ret.setLinkable(aRule.getLinkableClone());
    // abstract is always false
    ret.setContext(m_aQueryBinding.getWithParamTextsReplaced(aRule.getContext(), aParamValueMap));
    ret.setID(aIDPool.getUniqueID(aRule.getID()));
    if (aRule.hasAnyInclude())
        throw new SchematronPreprocessException("Cannot preprocess <rule> with an <include>");
    for (final PSLet aLet : aRule.getAllLets()) ret.addLet(aLet.getClone());
    _resolveRuleContent(aRule.getAllContentElements(), aLookup, aIDPool, aParamValueMap, ret);
    ret.addForeignElements(aRule.getAllForeignElements());
    ret.addForeignAttributes(aRule.getAllForeignAttributes());
    return ret;
}
Also used : PSRule(com.helger.schematron.pure.model.PSRule) PSLet(com.helger.schematron.pure.model.PSLet) Nullable(javax.annotation.Nullable)

Example 5 with PSRule

use of com.helger.schematron.pure.model.PSRule in project ph-schematron by phax.

the class PSXPathBoundSchema method validate.

public void validate(@Nonnull final Node aNode, @Nullable final String sBaseURI, @Nonnull final IPSValidationHandler aValidationHandler) throws SchematronValidationException {
    ValueEnforcer.notNull(aNode, "Node");
    ValueEnforcer.notNull(aValidationHandler, "ValidationHandler");
    if (m_aBoundPatterns == null)
        throw new IllegalStateException("bind was never called!");
    final PSSchema aSchema = getOriginalSchema();
    final PSPhase aPhase = getPhase();
    // Call the "start" callback method
    aValidationHandler.onStart(aSchema, aPhase, sBaseURI);
    // For all bound patterns
    for (final PSXPathBoundPattern aBoundPattern : m_aBoundPatterns) {
        final PSPattern aPattern = aBoundPattern.getPattern();
        aValidationHandler.onPattern(aPattern);
        // For all bound rules
        rules: for (final PSXPathBoundRule aBoundRule : aBoundPattern.getAllBoundRules()) {
            final PSRule aRule = aBoundRule.getRule();
            // Find all nodes matching the rules
            NodeList aRuleMatchingNodes = null;
            try {
                aRuleMatchingNodes = XPathEvaluationHelper.evaluate(aBoundRule.getBoundRuleExpression(), aNode, XPathConstants.NODESET, sBaseURI);
            } catch (final XPathExpressionException ex) {
                // Handle the cause, because it is usually a wrapper only
                error(aRule, "Failed to evaluate XPath expression to a nodeset: '" + aBoundRule.getRuleExpression() + "'", ex.getCause() != null ? ex.getCause() : ex);
                continue rules;
            }
            final int nRuleMatchingNodes = aRuleMatchingNodes.getLength();
            if (nRuleMatchingNodes > 0) {
                // For all contained assert and report elements
                for (final PSXPathBoundAssertReport aBoundAssertReport : aBoundRule.getAllBoundAssertReports()) {
                    // XSLT does "fired-rule" for each node
                    aValidationHandler.onRule(aRule, aBoundRule.getRuleExpression());
                    final PSAssertReport aAssertReport = aBoundAssertReport.getAssertReport();
                    final boolean bIsAssert = aAssertReport.isAssert();
                    final XPathExpression aTestExpression = aBoundAssertReport.getBoundTestExpression();
                    // Check each node, if it matches the assert/report
                    for (int i = 0; i < nRuleMatchingNodes; ++i) {
                        final Node aRuleMatchingNode = aRuleMatchingNodes.item(i);
                        try {
                            final boolean bTestResult = ((Boolean) XPathEvaluationHelper.evaluate(aTestExpression, aRuleMatchingNode, XPathConstants.BOOLEAN, sBaseURI)).booleanValue();
                            if (bIsAssert) {
                                // It's an assert
                                if (!bTestResult) {
                                    // Assert failed
                                    if (aValidationHandler.onFailedAssert(aAssertReport, aBoundAssertReport.getTestExpression(), aRuleMatchingNode, i, aBoundAssertReport).isBreak()) {
                                        return;
                                    }
                                }
                            } else {
                                // It's a report
                                if (bTestResult) {
                                    // Successful report
                                    if (aValidationHandler.onSuccessfulReport(aAssertReport, aBoundAssertReport.getTestExpression(), aRuleMatchingNode, i, aBoundAssertReport).isBreak()) {
                                        return;
                                    }
                                }
                            }
                        } catch (final XPathExpressionException ex) {
                            error(aRule, "Failed to evaluate XPath expression to a boolean: '" + aBoundAssertReport.getTestExpression() + "'", ex.getCause() != null ? ex.getCause() : ex);
                        }
                    }
                }
                if (false) {
                    // the next pattern
                    break rules;
                }
            }
        }
    }
    // Call the "end" callback method
    aValidationHandler.onEnd(aSchema, aPhase);
}
Also used : XPathExpression(javax.xml.xpath.XPathExpression) PSRule(com.helger.schematron.pure.model.PSRule) XPathExpressionException(javax.xml.xpath.XPathExpressionException) NodeList(org.w3c.dom.NodeList) Node(org.w3c.dom.Node) PSSchema(com.helger.schematron.pure.model.PSSchema) PSPhase(com.helger.schematron.pure.model.PSPhase) PSAssertReport(com.helger.schematron.pure.model.PSAssertReport) PSPattern(com.helger.schematron.pure.model.PSPattern)

Aggregations

PSRule (com.helger.schematron.pure.model.PSRule)5 PSAssertReport (com.helger.schematron.pure.model.PSAssertReport)3 PSLet (com.helger.schematron.pure.model.PSLet)3 PSPattern (com.helger.schematron.pure.model.PSPattern)3 Nullable (javax.annotation.Nullable)3 IPSElement (com.helger.schematron.pure.model.IPSElement)2 XPathExpression (javax.xml.xpath.XPathExpression)2 XPathExpressionException (javax.xml.xpath.XPathExpressionException)2 CommonsArrayList (com.helger.commons.collection.impl.CommonsArrayList)1 CommonsHashMap (com.helger.commons.collection.impl.CommonsHashMap)1 ICommonsMap (com.helger.commons.collection.impl.ICommonsMap)1 IPSXPathVariables (com.helger.schematron.pure.binding.xpath.IPSXPathVariables)1 PSXPathVariables (com.helger.schematron.pure.binding.xpath.PSXPathVariables)1 PSExtends (com.helger.schematron.pure.model.PSExtends)1 PSPhase (com.helger.schematron.pure.model.PSPhase)1 PSSchema (com.helger.schematron.pure.model.PSSchema)1 Map (java.util.Map)1 Node (org.w3c.dom.Node)1 NodeList (org.w3c.dom.NodeList)1