001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package dev.metaschema.core.metapath; 007 008import dev.metaschema.core.metapath.item.IItem; 009import edu.umd.cs.findbugs.annotations.NonNull; 010 011/** 012 * Represents the focus context for Metapath evaluation, containing the context 013 * item, position, and size as defined in the 014 * <a href="https://www.w3.org/TR/xpath-31/#eval_context">XPath 3.1 evaluation 015 * context</a>. 016 * <p> 017 * The focus context is established when evaluating predicates and provides the 018 * information needed by the {@code fn:position()} and {@code fn:last()} 019 * functions. 020 */ 021public final class FocusContext { 022 @NonNull 023 private final IItem contextItem; 024 private final int position; 025 private final int size; 026 027 private FocusContext(@NonNull IItem contextItem, int position, int size) { 028 this.contextItem = contextItem; 029 this.position = position; 030 this.size = size; 031 } 032 033 /** 034 * Create a new focus context for the given item at the specified position 035 * within a sequence. 036 * 037 * @param item 038 * the context item 039 * @param position 040 * the 1-based position of the item within the sequence 041 * @param size 042 * the total number of items in the sequence 043 * @return a new focus context 044 * @throws IllegalArgumentException 045 * if position is less than 1, size is less than 1, or position is 046 * greater than size 047 */ 048 @NonNull 049 public static FocusContext of(@NonNull IItem item, int position, int size) { 050 if (position < 1) { 051 throw new IllegalArgumentException("Position must be >= 1, got: " + position); 052 } 053 if (size < 1) { 054 throw new IllegalArgumentException("Size must be >= 1, got: " + size); 055 } 056 if (position > size) { 057 throw new IllegalArgumentException( 058 String.format("Position (%d) cannot be greater than size (%d)", position, size)); 059 } 060 return new FocusContext(item, position, size); 061 } 062 063 /** 064 * Get the context item. 065 * 066 * @return the context item 067 */ 068 @NonNull 069 public IItem getContextItem() { 070 return contextItem; 071 } 072 073 /** 074 * Get the context position. 075 * <p> 076 * This is the 1-based position of the context item within the sequence 077 * currently being processed, as returned by {@code fn:position()}. 078 * 079 * @return the context position (1-based) 080 */ 081 public int getPosition() { 082 return position; 083 } 084 085 /** 086 * Get the context size. 087 * <p> 088 * This is the total number of items in the sequence currently being processed, 089 * as returned by {@code fn:last()}. 090 * 091 * @return the context size 092 */ 093 public int getSize() { 094 return size; 095 } 096}