| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.xml.impl.schema; |
| |
| import com.intellij.codeInsight.daemon.Validator; |
| import com.intellij.codeInsight.daemon.XmlErrorMessages; |
| import com.intellij.psi.PsiElement; |
| import com.intellij.psi.xml.XmlAttribute; |
| import com.intellij.psi.xml.XmlTag; |
| import com.intellij.xml.XmlElementDescriptor; |
| import com.intellij.xml.util.XmlUtil; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.HashMap; |
| |
| /** |
| * @author Maxim.Mossienko |
| */ |
| public class SchemaNSDescriptor extends XmlNSDescriptorImpl { |
| @NonNls private static final String MIN_OCCURS_ATTR_NAME = "minOccurs"; |
| @NonNls private static final String MAX_OCCURS_ATTR_VALUE = "maxOccurs"; |
| @NonNls private static final String MAX_OCCURS_ATTR_NAME = MAX_OCCURS_ATTR_VALUE; |
| @NonNls private static final String ID_ATTR_NAME = "id"; |
| @NonNls private static final String REF_ATTR_NAME = "ref"; |
| @NonNls private static final String DEFAULT_ATTR_NAME = "default"; |
| @NonNls private static final String FIXED_ATTR_NAME = "fixed"; |
| |
| @NonNls private static final String NAME_ATTR_NAME = "name"; |
| |
| private static final Validator<XmlTag> ELEMENT_VALIDATOR = new Validator<XmlTag>() { |
| @Override |
| public void validate(@NotNull final XmlTag tag, @NotNull ValidationHost host) { |
| if (!isFromSchemaNs(tag)) return; |
| final boolean hasRefAttribute = tag.getAttributeValue(REF_ATTR_NAME) != null; |
| |
| if (hasRefAttribute) { |
| for(XmlAttribute attr:tag.getAttributes()) { |
| final String name = attr.getName(); |
| |
| if (name.indexOf(':') == -1 && |
| !MIN_OCCURS_ATTR_NAME.equals(name) && |
| !MAX_OCCURS_ATTR_NAME.equals(name) && |
| !ID_ATTR_NAME.equals(name) && |
| !REF_ATTR_NAME.equals(name)) { |
| host.addMessage( |
| attr.getNameElement(), |
| XmlErrorMessages.message("xml.schema.validation.attr.not.allowed.with.ref", name), |
| ValidationHost.ErrorType.ERROR |
| ); |
| } |
| } |
| } |
| |
| final String minOccursValue = tag.getAttributeValue("minOccurs"); |
| final String maxOccursValue = tag.getAttributeValue(MAX_OCCURS_ATTR_VALUE); |
| |
| if (minOccursValue != null && maxOccursValue != null) { |
| try { |
| final int minOccurs = Integer.parseInt(minOccursValue); |
| final int maxOccurs = Integer.parseInt(maxOccursValue); |
| if (maxOccurs < minOccurs) { |
| host.addMessage( |
| tag.getAttribute(MAX_OCCURS_ATTR_VALUE, null).getValueElement(), |
| XmlErrorMessages.message("xml.schema.validation.max.occurs.should.be.not.less.than.min.occurs"), |
| ValidationHost.ErrorType.ERROR |
| ); |
| } |
| } |
| catch (NumberFormatException e) { |
| // this schema will be reported by xerces validation |
| } |
| } |
| |
| if (!hasRefAttribute && tag.getAttributeValue(NAME_ATTR_NAME) == null) { |
| host.addMessage( |
| tag, |
| XmlErrorMessages.message("xml.schema.validation.name.or.ref.should.present"), |
| ValidationHost.ErrorType.ERROR |
| ); |
| } |
| } |
| }; |
| |
| private static final Validator<XmlTag> ATTRIBUTE_VALIDATOR = new Validator<XmlTag>() { |
| @Override |
| public void validate(@NotNull final XmlTag tag, @NotNull ValidationHost host) { |
| if (!isFromSchemaNs(tag)) return; |
| |
| if (tag.getAttributeValue(REF_ATTR_NAME) == null && tag.getAttributeValue(NAME_ATTR_NAME) == null) { |
| host.addMessage( |
| tag, |
| XmlErrorMessages.message("xml.schema.validation.name.or.ref.should.present"), |
| ValidationHost.ErrorType.ERROR |
| ); |
| } |
| |
| if (tag.getAttributeValue(DEFAULT_ATTR_NAME) != null && tag.getAttributeValue(FIXED_ATTR_NAME) != null) { |
| host.addMessage( |
| tag.getAttribute(DEFAULT_ATTR_NAME, null).getNameElement(), |
| XmlErrorMessages.message("xml.schema.validation.default.or.fixed.should.be.specified.but.not.both"), |
| ValidationHost.ErrorType.ERROR |
| ); |
| |
| host.addMessage( |
| tag.getAttribute(FIXED_ATTR_NAME, null).getNameElement(), |
| XmlErrorMessages.message("xml.schema.validation.default.or.fixed.should.be.specified.but.not.both"), |
| ValidationHost.ErrorType.ERROR |
| ); |
| } |
| } |
| }; |
| |
| private static final XmlUtil.DuplicationInfoProvider<XmlTag> SCHEMA_ATTR_DUP_INFO_PROVIDER = new XmlUtil.DuplicationInfoProvider<XmlTag>() { |
| @Override |
| public String getName(@NotNull final XmlTag t) { |
| return t.getAttributeValue(NAME_ATTR_NAME); |
| } |
| |
| @Override |
| @NotNull |
| public String getNameKey(@NotNull final XmlTag t, @NotNull String name) { |
| return name; |
| } |
| |
| @Override |
| @NotNull |
| public PsiElement getNodeForMessage(@NotNull final XmlTag t) { |
| return t.getAttribute(NAME_ATTR_NAME, null).getValueElement(); |
| } |
| }; |
| |
| private static final Validator<XmlTag> ELEMENT_AND_ATTR_VALIDATOR = new Validator<XmlTag>() { |
| @Override |
| public void validate(@NotNull final XmlTag tag, @NotNull ValidationHost host) { |
| if (!isFromSchemaNs(tag)) return; |
| final String nsPrefix = tag.getNamespacePrefix(); |
| final XmlTag[] attrDeclTags = tag.findSubTags((nsPrefix.length() > 0 ? nsPrefix + ":" : "") + "attribute"); |
| |
| XmlUtil.doDuplicationCheckForElements( |
| attrDeclTags, |
| new HashMap<String, XmlTag>(attrDeclTags.length), |
| SCHEMA_ATTR_DUP_INFO_PROVIDER, |
| host |
| ); |
| |
| final XmlTag[] elementDeclTags = tag.findSubTags((nsPrefix.length() > 0 ? nsPrefix + ":" : "") + "element"); |
| |
| XmlUtil.doDuplicationCheckForElements( |
| elementDeclTags, |
| new HashMap<String, XmlTag>(elementDeclTags.length), |
| SCHEMA_ATTR_DUP_INFO_PROVIDER, |
| host |
| ); |
| } |
| }; |
| |
| private static boolean isFromSchemaNs(final XmlTag tag) { |
| return XmlUtil.XML_SCHEMA_URI.equals(tag.getNamespace()); |
| } |
| |
| @Override |
| protected XmlElementDescriptor createElementDescriptor(final XmlTag tag) { |
| final XmlElementDescriptor descriptor = super.createElementDescriptor(tag); |
| String localName = tag.getAttributeValue(NAME_ATTR_NAME); |
| if (ELEMENT_TAG_NAME.equals(localName)) { |
| ((XmlElementDescriptorImpl)descriptor).setValidator(ELEMENT_VALIDATOR); |
| } else if (COMPLEX_TYPE_TAG_NAME.equals(localName) || SCHEMA_TAG_NAME.equals(localName) || SEQUENCE_TAG_NAME.equals(localName)) { |
| ((XmlElementDescriptorImpl)descriptor).setValidator(ELEMENT_AND_ATTR_VALIDATOR); |
| } else if (ATTRIBUTE_TAG_NAME.equals(localName)) { |
| ((XmlElementDescriptorImpl)descriptor).setValidator(ATTRIBUTE_VALIDATOR); |
| } |
| return descriptor; |
| } |
| |
| @Override |
| public String toString() { |
| return getDefaultNamespace(); |
| } |
| } |