/** * Returns the {@link StartTag} beginning at or immediately following the specified position in the source document. * <p> * See the {@link Tag} class documentation for more details about the behaviour of this method. * * @param pos the position in the source document from which to start the search, may be out of bounds. * @return the {@link StartTag} beginning at or immediately following the specified position in the source document, or <code>null</code> if none exists or the specified position is out of bounds. */ public StartTag getNextStartTag(final int pos) { return StartTag.getNext(this,pos); }
/** * Returns a list of all {@link StartTag} objects that are {@linkplain #encloses(Segment) enclosed} by this segment. * <p> * The {@link Source#fullSequentialParse()} method should be called after construction of the {@link Source} object * if this method is to be used on a large proportion of the source. * It is called automatically if this method is called on the {@link Source} object itself. * <p> * See the {@link Tag} class documentation for more details about the behaviour of this method. * * @return a list of all {@link StartTag} objects that are {@linkplain #encloses(Segment) enclosed} by this segment. */ public List<StartTag> getAllStartTags() { StartTag startTag=checkEnclosure(StartTag.getNext(source,begin)); if (startTag==null) return Collections.emptyList(); final ArrayList<StartTag> list=new ArrayList<StartTag>(); do { list.add(startTag); startTag=checkEnclosure(startTag.getNextStartTag()); } while (startTag!=null); return list; }
final boolean isXMLTagName=Tag.isXMLName(name); name=name.toLowerCase(); StartTag startTag=checkEnclosure(StartTag.getNext(source,begin,name,StartTagType.NORMAL,isXMLTagName)); if (startTag==null) return Collections.emptyList(); final ArrayList<StartTag> list=new ArrayList<StartTag>(); do { list.add(startTag); startTag=checkEnclosure(StartTag.getNext(source,startTag.begin+1,name,StartTagType.NORMAL,isXMLTagName)); } while (startTag!=null);
/** * Returns the first {@link Element} {@linkplain #encloses(Segment) enclosed} by this segment. * <p> * This is functionally equivalent to {@link #getAllElements()}<code>.iterator().next()</code>, * but does not search beyond the first enclosed element and returns <code>null</code> if no such element exists. * <p> * If this segment is itself an {@link Element}, this element is returned, not the first child element. * * @return the first {@link Element} {@linkplain #encloses(Segment) enclosed} by this segment, or <code>null</code> if none exists. */ public final Element getFirstElement() { StartTag startTag=checkEnclosure(StartTag.getNext(source,begin)); while (startTag!=null) { final Element element=startTag.getElement(); if (element.end<=end) return element; startTag=checkEnclosure(startTag.getNextStartTag()); } return null; }
static StartTag getNext(final Source source, final int pos, final String searchName, final StartTagType searchStartTagType, final boolean isXMLTagName) { // searchName is already in lower case, but may be null // searchStartTagType must not be null // searchStartTagType may be something other than NORMAL together with a searchName when called from Source.getNextStartTag(pos,name,startTagType) or when searching for nested start tags during internal end tag search. // isXMLTagName is only used if searchStartTagType==StartTagType.NORMAL, otherwise it is always true. if (searchName==null) return (StartTag)source.getNextTag(pos,searchStartTagType); if (source.wasFullSequentialParseCalled() && isXMLTagName) { // This cache search only finds tags of the specified type, so don't do it if !isXMLTagName because the user might be looking for UNREGISTERED tags using standard name search. // We still might reach here if the user called Source.getNextStartTag(pos,name,startTagType) StartTag startTag=(StartTag)Tag.getNextTag(source,pos,searchStartTagType); while (true) { if (startTag==null) return null; if (startTag.name.equals(searchName)) return startTag; if (startTag.name.startsWith(searchName) && startTag.isPartialNameSearchMatch(searchName)) return startTag; if (startTag.name.length()<searchName.length() && source.getParseText().containsAt(searchName,startTag.begin+searchStartTagType.startDelimiterPrefix.length())) return startTag; startTag=(StartTag)startTag.getNextTag(searchStartTagType); } } else { final String startDelimiter=getStartDelimiter(searchName); try { final ParseText parseText=source.getParseText(); int begin=pos; do { begin=parseText.indexOf(startDelimiter,begin); if (begin==-1) return null; final StartTag startTag=(StartTag)Tag.getTagAt(source,begin,false); if (startTag==null) continue; // keep looking if it wasn't a start tag if (searchStartTagType!=startTag.getStartTagType()) { // The start tag is of the wrong type. The only case in which we want to return it is if // we are looking for a normal start tag, the found start tag is unregistered, and the search name is NOT a valid XML name.
/** * Returns the {@link StartTag} with the specified attribute name/value pair beginning at or immediately following the specified position in the source document. * <p> * See the {@link Tag} class documentation for more details about the behaviour of this method. * * @param pos the position in the source document from which to start the search, may be out of bounds. * @param attributeName the attribute name (case insensitive) to search for, must not be <code>null</code>. * @param value the value of the specified attribute to search for, must not be <code>null</code>. * @param valueCaseSensitive specifies whether the attribute value matching is case sensitive. * @return the {@link StartTag} with the specified attribute name/value pair beginning at or immediately following the specified position in the source document, or <code>null</code> if none exists or the specified position is out of bounds. * @see #getNextStartTag(int pos, String attributeName, Pattern valueRegexPattern) */ public StartTag getNextStartTag(final int pos, final String attributeName, final String value, final boolean valueCaseSensitive) { return StartTag.getNext(this,pos,attributeName,value,valueCaseSensitive); }
/** * Returns the {@link StartTag} with the specified attribute name and value pattern beginning at or immediately following the specified position in the source document. * <p> * Specifying a <code>null</code> argument to the <code>valueRegexPattern</code> parameter performs the search on the attribute name only, * without regard to the attribute value. This will also match an attribute that {@linkplain Attribute#hasValue() has no value} at all. * <p> * See the {@link Tag} class documentation for more details about the behaviour of this method. * * @param pos the position in the source document from which to start the search, may be out of bounds. * @param attributeName the attribute name (case insensitive) to search for, must not be <code>null</code>. * @param valueRegexPattern the regular expression pattern that must match the attribute value, may be <code>null</code>. * @return the {@link StartTag} with the specified attribute name and value pattern beginning at or immediately following the specified position in the source document, or <code>null</code> if none exists or the specified position is out of bounds. * @see #getNextStartTag(int pos, String attributeName, String value, boolean valueCaseSensitive) */ public StartTag getNextStartTag(final int pos, final String attributeName, final Pattern valueRegexPattern) { return StartTag.getNext(this,pos,attributeName,valueRegexPattern); }
/** * Returns the {@link StartTag} with the specified {@linkplain StartTag#getName() name} and {@linkplain StartTagType type} beginning at or immediately following the specified position in the source document. * <p> * See the {@link Tag} class documentation for more details about the behaviour of this method. * <p> * Specifying {@link StartTagType#NORMAL} as the argument to the <code>startTagType</code> parameter is equivalent to * {@link #getNextStartTag(int,String) getNextStartTag(pos,name)}. * * @param pos the position in the source document from which to start the search, may be out of bounds. * @param name the {@linkplain StartTag#getName() name} of the start tag to search for, may be <code>null</code>. * @param startTagType the {@linkplain StartTagType type} of the start tag to search for, must not be <code>null</code>. * @return the {@link StartTag} with the specified {@linkplain StartTag#getName() name} and {@linkplain StartTagType type} beginning at or immediately following the specified position in the source document, or <code>null</code> if none exists or the specified position is out of bounds. */ public StartTag getNextStartTag(final int pos, String name, final StartTagType startTagType) { if (name!=null) name=name.toLowerCase(); return StartTag.getNext(this,pos,name,startTagType); }
private Segment[] getEndTag(final EndTag nextEndTag, final boolean checkForEmptyElementTag, final boolean isXMLTagName) { assert nextEndTag!=null; StartTag nextStartTag=getNext(source,end,name,startTagType,isXMLTagName); if (checkForEmptyElementTag) { while (nextStartTag!=null && nextStartTag.isSyntacticalEmptyElementTag()) nextStartTag=getNext(source,nextStartTag.end,name,startTagType,isXMLTagName); } return getEndTag(end,nextStartTag,nextEndTag,checkForEmptyElementTag,isXMLTagName); }
/** * Returns the first {@linkplain StartTagType#NORMAL normal} {@link Element} with the specified {@linkplain Element#getName() name} {@linkplain #encloses(Segment) enclosed} by this segment. * <p> * This is functionally equivalent to {@link #getAllElements(String) getAllElements(name)}<code>.iterator().next()</code>, * but does not search beyond the first enclosed element and returns <code>null</code> if no such element exists. * <p> * Specifying a <code>null</code> argument to the <code>name</code> parameter is equivalent to {@link #getFirstElement()}. * <p> * If this segment is itself an {@link Element} with the specified name, this element is returned. * * @param name the {@linkplain Element#getName() name} of the element to search for. * @return the first {@linkplain StartTagType#NORMAL normal} {@link Element} with the specified {@linkplain Element#getName() name} {@linkplain #encloses(Segment) enclosed} by this segment, or <code>null</code> if none exists. */ public final Element getFirstElement(String name) { if (name==null) return getFirstElement(); final boolean isXMLTagName=Tag.isXMLName(name); name=name.toLowerCase(); StartTag startTag=checkEnclosure(StartTag.getNext(source,begin,name,StartTagType.NORMAL,isXMLTagName)); while (startTag!=null) { final Element element=startTag.getElement(); if (element.end<=end) return element; startTag=checkEnclosure(StartTag.getNext(source,startTag.begin+1,name,StartTagType.NORMAL,isXMLTagName)); } return null; }