001/**
002 *
003 * Copyright 2015 Florian Schmaus.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smack.parsing;
018
019import java.io.IOException;
020import java.util.LinkedHashMap;
021import java.util.Map;
022
023import org.jivesoftware.smack.packet.StandardExtensionElement;
024import org.jivesoftware.smack.packet.StandardExtensionElement.Builder;
025import org.jivesoftware.smack.provider.ExtensionElementProvider;
026import org.jivesoftware.smack.util.ParserUtils;
027import org.jivesoftware.smack.util.StringUtils;
028
029import org.xmlpull.v1.XmlPullParser;
030import org.xmlpull.v1.XmlPullParserException;
031
032/**
033 * The parser for {@link StandardExtensionElement}s.
034 *
035 * @author Florian Schmaus
036 *
037 */
038public class StandardExtensionElementProvider extends ExtensionElementProvider<StandardExtensionElement> {
039
040    public static StandardExtensionElementProvider INSTANCE = new StandardExtensionElementProvider();
041
042    @Override
043    public StandardExtensionElement parse(final XmlPullParser parser, final int initialDepth)
044                    throws XmlPullParserException, IOException {
045        // Unlike most (all?) other providers, we don't know the name and namespace of the element
046        // we are parsing here.
047        String name = parser.getName();
048        String namespace = parser.getNamespace();
049        Builder builder = StandardExtensionElement.builder(name, namespace);
050        final int namespaceCount = parser.getNamespaceCount(initialDepth);
051        final int attributeCount = parser.getAttributeCount();
052        final Map<String, String> attributes = new LinkedHashMap<>(namespaceCount + attributeCount);
053        for (int i = 0; i < namespaceCount; i++) {
054            String nsprefix = parser.getNamespacePrefix(i);
055            if (nsprefix == null) {
056                // Skip the default namespace.
057                continue;
058            }
059            // XmlPullParser must either return null or a non-empty String.
060            assert StringUtils.isNotEmpty(nsprefix);
061            String nsuri = parser.getNamespaceUri(i);
062            attributes.put("xmlns:" + nsprefix, nsuri);
063        }
064        for (int i = 0; i < attributeCount; i++) {
065            String attributePrefix = parser.getAttributePrefix(i);
066            String attributeName = parser.getAttributeName(i);
067            String attributeValue = parser.getAttributeValue(i);
068            String attributeKey;
069            if (StringUtils.isNullOrEmpty(attributePrefix)) {
070                attributeKey = attributeName;
071            }
072            else {
073                attributeKey = attributePrefix + ':' + attributeName;
074            }
075            attributes.put(attributeKey, attributeValue);
076        }
077        builder.addAttributes(attributes);
078
079        outerloop: while (true) {
080            int event = parser.next();
081            switch (event) {
082            case XmlPullParser.START_TAG:
083                builder.addElement(parse(parser, parser.getDepth()));
084                break;
085            case XmlPullParser.TEXT:
086                builder.setText(parser.getText());
087                break;
088            case XmlPullParser.END_TAG:
089                if (initialDepth == parser.getDepth()) {
090                    break outerloop;
091                }
092                break;
093            }
094        }
095
096        ParserUtils.assertAtEndTag(parser);
097        return builder.build();
098    }
099}