blob: fc750777a60b5653100141c0b3abe4065d50c289 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
/*
* PositionFinderVisitor.java
*
* Created on October 26, 2005, 3:02 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package org.netbeans.modules.xml.xdm.visitor;
import java.util.List;
import org.netbeans.modules.xml.xdm.nodes.Attribute;
import org.netbeans.modules.xml.xdm.nodes.Document;
import org.netbeans.modules.xml.xdm.nodes.Element;
import org.netbeans.modules.xml.xdm.nodes.Node;
import org.netbeans.modules.xml.xdm.nodes.NodeImpl;
import org.netbeans.modules.xml.xdm.nodes.Text;
import org.netbeans.modules.xml.xdm.nodes.Token;
import org.netbeans.modules.xml.xdm.nodes.TokenType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
/**
*
* @author rico
*/
public class PositionFinderVisitor implements XMLNodeVisitor{
int position = 0;
Node node;
boolean found;
public int findPosition(Node rootNode, Node node){
reset();
this.node = node;
rootNode.accept(this);
return position;
}
public void reset(){
position = 0;
found = false;
}
public void visit(Document doc) {
//xml processing instruction
position += getLengthOfTokens(doc);
NodeList nodes = doc.getChildNodes();
for(int i = 0; i < nodes.getLength(); i++){
Node n = (Node)nodes.item(i);
n.accept(this);
if(found) return;
}
}
public void visit(Element e) {
if(e.getId() == node.getId()){
found = true;
} else{
position += getElementStartTokenLength(e, true); //open start tag
NamedNodeMap attrs = e.getAttributes();
for(int i = 0; i < attrs.getLength(); i++){
Node attr = (Node)attrs.item(i);
attr.accept(this);
if(found) return;
}
position += getStartTagWhiteSpaceTokensLength(e); //all whitespaces
position++; //close of start tag
NodeList children = e.getChildNodes();
for(int i = 0; i < children.getLength(); i++){
Node n = (Node)children.item(i);
n.accept(this);
if(found) return;
}
position += getElementStartTokenLength(e, false); //open end tag
position += getEndTagWhiteSpaceTokensLength(e); //all whitespaces
position++; //close of end tag
}
}
public void visit(Text txt) {
if(txt.getId() == node.getId()){
found = true;
} else{
int txtLen = getLength(txt);
if(txtLen > 0)
position += txtLen;
}
}
public void visit(Attribute attr) {
if(attr.getId() == node.getId()){
//add preceding white spaces
position += getLeadingWhiteSpaces(attr);
found = true;
} else{
position += getLengthOfTokens(attr);
}
}
private int getLength(Text n) {
int len = 0;
for(Token token:((NodeImpl)n).getTokens())
len += token.getValue().length();
return len;
}
/**
* Obtains the length of a start token of elements, e.g., "<", or "<elementname",
* "</", or "</elementname".
* @param node The element being queried
* @param beginTag Is this for the start tag (<) or end tag (</)?
* @return length of start element
*/
private int getElementStartTokenLength(Element element, boolean beginTag){
String value = "";
List<Token> tokens = element.getTokens();
for(Token token : tokens){
if(token.getType() != TokenType.TOKEN_ELEMENT_START_TAG){
continue;
}
String tokenValue = token.getValue();
if(beginTag){
if(!tokenValue.startsWith("</")){
value = tokenValue;
}
} else{ //end tag
if(tokenValue.startsWith("</")){
value = tokenValue;
}
}
}
return value.length();
}
private int getStartTagWhiteSpaceTokensLength(NodeImpl node){
StringBuilder buf = new StringBuilder();
List<Token> tokens = node.getTokens();
for(Token token : tokens){
if (token.getType() == TokenType.TOKEN_ELEMENT_END_TAG){
break; // only count whitspace before first tag end
}
if (token.getType() == TokenType.TOKEN_WHITESPACE) {
buf.append(token.getValue());
}
}
return buf.toString().length();
}
private int getEndTagWhiteSpaceTokensLength(NodeImpl node){
StringBuilder buf = new StringBuilder();
List<Token> tokens = node.getTokens();
boolean counting = false;
for(Token token : tokens){
if (token.getType() == TokenType.TOKEN_ELEMENT_START_TAG){
if (token.getValue().startsWith("</")) {
counting = true;
}
}
if (! counting) continue;
if (token.getType() == TokenType.TOKEN_WHITESPACE) {
buf.append(token.getValue());
}
}
return buf.toString().length();
}
private int getLeadingWhiteSpaces(Attribute attr){
Token firstToken = attr.getTokens().get(0); //get the first token
if(firstToken.getType() == TokenType.TOKEN_WHITESPACE){
return firstToken.getValue().length();
}
return 0;
}
private int getLengthOfTokens(NodeImpl node){
StringBuilder buf = new StringBuilder();
List<Token> tokens = node.getTokens();
for(Token token : tokens){
buf.append(token.getValue());
}
return buf.length();
}
}