All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.java.com.amazon.ionpathextraction.SearchPathParser Maven / Gradle / Ivy

Go to download

Ion Path Extraction API aims to combine the convenience of a DOM API with the speed of a streaming API.

The newest version!
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at:
 *
 *     http://aws.amazon.com/apache2.0/
 *
 * or in the "license" file accompanying this file. This file 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.amazon.ionpathextraction;

import static com.amazon.ionpathextraction.internal.Preconditions.checkArgument;

import com.amazon.ion.IonReader;
import com.amazon.ion.IonType;
import com.amazon.ion.IonWriter;
import com.amazon.ion.system.IonReaderBuilder;
import com.amazon.ion.system.IonTextWriterBuilder;
import com.amazon.ionpathextraction.exceptions.PathExtractionException;
import com.amazon.ionpathextraction.internal.Annotations;
import com.amazon.ionpathextraction.pathcomponents.Index;
import com.amazon.ionpathextraction.pathcomponents.PathComponent;
import com.amazon.ionpathextraction.pathcomponents.Text;
import com.amazon.ionpathextraction.pathcomponents.Wildcard;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;

/**
 * Parses a search path ion expression into a {@link SearchPath}s.
 */
final class SearchPathParser {

    private static final IonReaderBuilder READER_BUILDER = IonReaderBuilder.standard();
    private static final IonTextWriterBuilder WRITER_BUILDER = IonTextWriterBuilder.standard();

    private static final String WILDCARD_ESCAPE_ANNOTATION = "$ion_extractor_field";

    // only has static methods, should not be invoked
    private SearchPathParser() {
    }

    static  SearchPath parse(final String ionPathExpression, final BiFunction callback) {
        final List pathComponents;

        try (final IonReader reader = newIonReader(ionPathExpression)) {
            checkArgument(reader.next() != null, "ionPathExpression cannot be empty");
            checkArgument(reader.getType() == IonType.SEXP || reader.getType() == IonType.LIST,
                "ionPathExpression must be a s-expression or list");

            final String[] typeAnnotations = reader.getTypeAnnotations();

            reader.stepIn();
            pathComponents = parsePathComponents(reader);
            reader.stepOut();

            return new SearchPath<>(pathComponents, callback, new Annotations(typeAnnotations));
        } catch (IOException e) {
            throw new PathExtractionException(e);
        }
    }

    private static List parsePathComponents(final IonReader reader) {
        final List pathComponents = new ArrayList<>();

        while (reader.next() != null) {
            pathComponents.add(readComponent(reader));
        }

        return pathComponents;
    }

    private static PathComponent readComponent(final IonReader reader) {
        final PathComponent pathComponent;
        final String[] annotations = extractAnnotations(reader);

        switch (reader.getType()) {
            case INT:
                pathComponent = new Index(reader.intValue(), annotations);
                break;

            case STRING:
            case SYMBOL:
                if (isWildcard(reader)) {
                    pathComponent = new Wildcard(annotations);
                } else {
                    pathComponent = new Text(reader.stringValue(), annotations);
                }
                break;

            default:
                throw new PathExtractionException("Invalid path component type: " + readIonText(reader));
        }

        return pathComponent;
    }

    private static String[] extractAnnotations(final IonReader reader) {
        String[] typeAnnotations = reader.getTypeAnnotations();

        final String[] annotations;
        final int offset;
        if (typeAnnotations.length > 0 && WILDCARD_ESCAPE_ANNOTATION.equals(typeAnnotations[0])) {
            annotations = new String[typeAnnotations.length - 1];
            offset = 1;
        } else {
            annotations = new String[typeAnnotations.length];
            offset = 0;
        }

        System.arraycopy(typeAnnotations, offset, annotations, 0, annotations.length);

        return annotations;
    }

    private static boolean isWildcard(final IonReader reader) {
        if (reader.stringValue().equals(Wildcard.TEXT)) {
            final String[] annotations = reader.getTypeAnnotations();
            return annotations.length == 0 || !WILDCARD_ESCAPE_ANNOTATION.equals(annotations[0]);
        }
        return false;
    }

    private static String readIonText(final IonReader reader) {
        StringBuilder out = new StringBuilder();
        try (IonWriter writer = newIonTextWriter(out)) {
            writer.writeValue(reader);
        } catch (IOException e) {
            throw new PathExtractionException(e);
        }
        return out.toString();
    }

    private static IonReader newIonReader(final String ionText) {
        return READER_BUILDER.build(ionText);
    }

    private static IonWriter newIonTextWriter(final StringBuilder out) {
        return WRITER_BUILDER.build(out);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy