001/*
002 * SPDX-FileCopyrightText: none
003 * SPDX-License-Identifier: CC0-1.0
004 */
005
006package dev.metaschema.databind.io.xml;
007
008import org.apache.logging.log4j.LogManager;
009import org.apache.logging.log4j.Logger;
010
011import java.util.HashSet;
012import java.util.Set;
013
014import javax.xml.stream.events.Attribute;
015
016import dev.metaschema.core.model.IBoundObject;
017import dev.metaschema.core.model.util.XmlEventUtil;
018import dev.metaschema.core.qname.IEnhancedQName;
019import dev.metaschema.core.util.ObjectUtils;
020import dev.metaschema.databind.io.AbstractProblemHandler;
021import dev.metaschema.databind.model.IBoundDefinitionModelComplex;
022
023/**
024 * Handles problems identified in the parsed XML.
025 * <p>
026 * The default problem handler will report unknown attributes, and provide empty
027 * collections for multi-valued model items and default values for flags and
028 * single valued fields.
029 */
030public class DefaultXmlProblemHandler
031    extends AbstractProblemHandler
032    implements IXmlProblemHandler {
033  private static final Logger LOGGER = LogManager.getLogger(DefaultXmlProblemHandler.class);
034
035  /**
036   * Construct a new problem handler with required field validation enabled.
037   */
038  public DefaultXmlProblemHandler() {
039    super();
040  }
041
042  /**
043   * Construct a new problem handler with the specified validation setting.
044   *
045   * @param validateRequiredFields
046   *          {@code true} to validate that required fields are present,
047   *          {@code false} to skip validation
048   */
049  public DefaultXmlProblemHandler(boolean validateRequiredFields) {
050    super(validateRequiredFields);
051  }
052
053  private static final IEnhancedQName XSI_SCHEMA_LOCATION
054      = IEnhancedQName.of("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
055  private static final Set<IEnhancedQName> IGNORED_QNAMES;
056
057  static {
058    IGNORED_QNAMES = new HashSet<>();
059    IGNORED_QNAMES.add(XSI_SCHEMA_LOCATION);
060  }
061
062  @Override
063  public boolean handleUnknownAttribute(
064      IBoundDefinitionModelComplex parentDefinition,
065      IBoundObject targetObject,
066      Attribute attribute,
067      IXmlParsingContext parsingContext) {
068    IEnhancedQName qname = IEnhancedQName.of(ObjectUtils.requireNonNull(attribute.getName()));
069    // check if warning is needed
070    if (LOGGER.isWarnEnabled() && !IGNORED_QNAMES.contains(qname)) {
071      LOGGER.atWarn().log("Skipping unrecognized attribute '{}'{}.",
072          qname,
073          XmlEventUtil.generateLocationMessage(
074              ObjectUtils.notNull(attribute.getLocation()),
075              parsingContext.getSource()));
076    }
077    // always ignore
078    return true;
079  }
080}