1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.databind.io.xml;
7   
8   import org.apache.logging.log4j.LogManager;
9   import org.apache.logging.log4j.Logger;
10  
11  import java.util.HashSet;
12  import java.util.Set;
13  
14  import javax.xml.stream.events.Attribute;
15  
16  import dev.metaschema.core.model.IBoundObject;
17  import dev.metaschema.core.model.util.XmlEventUtil;
18  import dev.metaschema.core.qname.IEnhancedQName;
19  import dev.metaschema.core.util.ObjectUtils;
20  import dev.metaschema.databind.io.AbstractProblemHandler;
21  import dev.metaschema.databind.model.IBoundDefinitionModelComplex;
22  
23  /**
24   * Handles problems identified in the parsed XML.
25   * <p>
26   * The default problem handler will report unknown attributes, and provide empty
27   * collections for multi-valued model items and default values for flags and
28   * single valued fields.
29   */
30  public class DefaultXmlProblemHandler
31      extends AbstractProblemHandler
32      implements IXmlProblemHandler {
33    private static final Logger LOGGER = LogManager.getLogger(DefaultXmlProblemHandler.class);
34  
35    /**
36     * Construct a new problem handler with required field validation enabled.
37     */
38    public DefaultXmlProblemHandler() {
39      super();
40    }
41  
42    /**
43     * Construct a new problem handler with the specified validation setting.
44     *
45     * @param validateRequiredFields
46     *          {@code true} to validate that required fields are present,
47     *          {@code false} to skip validation
48     */
49    public DefaultXmlProblemHandler(boolean validateRequiredFields) {
50      super(validateRequiredFields);
51    }
52  
53    private static final IEnhancedQName XSI_SCHEMA_LOCATION
54        = IEnhancedQName.of("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
55    private static final Set<IEnhancedQName> IGNORED_QNAMES;
56  
57    static {
58      IGNORED_QNAMES = new HashSet<>();
59      IGNORED_QNAMES.add(XSI_SCHEMA_LOCATION);
60    }
61  
62    @Override
63    public boolean handleUnknownAttribute(
64        IBoundDefinitionModelComplex parentDefinition,
65        IBoundObject targetObject,
66        Attribute attribute,
67        IXmlParsingContext parsingContext) {
68      IEnhancedQName qname = IEnhancedQName.of(ObjectUtils.requireNonNull(attribute.getName()));
69      // check if warning is needed
70      if (LOGGER.isWarnEnabled() && !IGNORED_QNAMES.contains(qname)) {
71        LOGGER.atWarn().log("Skipping unrecognized attribute '{}'{}.",
72            qname,
73            XmlEventUtil.generateLocationMessage(
74                ObjectUtils.notNull(attribute.getLocation()),
75                parsingContext.getSource()));
76      }
77      // always ignore
78      return true;
79    }
80  }