Opcões de Filtragem de Elementos
Para facilitar o processamento, JColtrane apresenta algumas opções para filtrar elementos do XML de acordo com o desejo do usuário. Para ilustrar essas opções, usaremos o código XML abaixo:
<?xml version="1.0" encoding="UTF-8"?>
<beanDescriptor>
<line>
<property mandatory="true" page="4" language="pt" />
<property2 mandatory="false" language="pt" />
</line>
</beanDescriptor>
Seguindo os passos apresentados na seção Clássico "Hello World" com JColtrane,
vamos construir uma classe básica para executar algumas ações quando estiver iniciando a finalizando um elemento:
public class StartAndEndElemetAction {
@StartElement
public void executeInStartElement(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in start element\n");
}
@EndElement
public void executeInEndElement(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in end element\n");
}
}
Agora, codificaremos uma classe passando a anterior como parâmetro para o JColtraneXMLHandler:
public class FilteringTest {
public static void main(String[] args) {
SAXParser parser=null;
try {
parser= SAXParserFactory.newInstance().newSAXParser();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
File file=new File("examples\\example2\\Example2.xml");
if(parser!=null){
InputSource input=new InputSource(file.getAbsolutePath());
try {
parser.parse(input,new JColtraneXMLHandler(new StartAndEndElemetAction()));
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Rodando a classe anterior, o sistema imprime:
/beanDescriptor/
Executing something in start element
/beanDescriptor/line/
Executing something in start element
/beanDescriptor/line/property/
Executing something in start element
/beanDescriptor/line/property/
Executing something in end element
/beanDescriptor/line/property2/
Executing something in start element
/beanDescriptor/line/property2/
Executing something in end element
/beanDescriptor/line/
Executing something in end element
/beanDescriptor/
Executing something in end element
Como você pode ver, o JColtrane executou o que queríamos: invocou os métodos quando estava iniciando ou finalizando qualquer elemento. Mas vamos dizer que você quisesse executar o primeiro método somente quando um elemento contendo a tag "line" iniciasse e quisesse, ainda, que o segundo método executasse somente quando qualquer elemento contendo a tag com sufixo "property" estivesse terminando . Para fazer isso, faremos as alterações marcadas no código de StartAndEndElementAction:
public class StartAndEndElemetAction {
@StartElement(tag="line")
public void executeInStartElement(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in start element\n");
}
@EndElement(tag="property.*")
public void executeInEndElement(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in end element\n");
}
}
Executando FilteringTest novamente, o sistema imprime:
/beanDescriptor/line/
Executing something in start element
/beanDescriptor/line/property/
Executing something in end element
/beanDescriptor/line/property2/
Executing something in end elemen
Como você pode ver, JColtrane fêz exatamente o que queríamos. No primeiro método colocamos a propriedade tag com valor "line". No segundo, colocamos o valor "property.*". Esse último valor é uma expressão regular. Assim, você pode usar expressões regulares (regex do JAVA) para filtrar elementos.
Além da propriedade tag , você pode usar as propriedades uri e localName também. Essas propriedades recebem, respectivamente, uri e nome local do elemento.
Vamos considerar agora que você deseje executar um método quando um elemento está finalizando e contenha um atributo de nome "mandatory". Você deseja executar outro método com uma condição similar, mas quer uma condição adicional, quer que o elemento contenha um atributo de nome "page" com valor "4" e que contenha também um atributo contenha o valor "pt". Para fazer isso, escrevemos a seguinte classe:
public class EndElemetAction {
@EndElement(attributes={@ContainAttribute(name="mandatory")})
public void executeInEndElement1(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in end element with attribute mandatory\n");
}
@EndElement(attributes={@ContainAttribute(name="mandatory"),@ContainAttribute(name="page",value="4")})
public void executeInEndElement2(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in end element with some attribute with name mandatory and another with name page and value 4\n");
}
@EndElement(attributes={@ContainAttribute(value="pt")})
public void executeInEndElement3(@CurrentBranch String currentBrunch){
System.out.println(currentBranch);
System.out.println("Executing something in end element with some attribute with value pt\n");
}
}
Rodando um teste, passando a classe acima, como fizemos nos demais exemplos, o sistema imprime:
/beanDescriptor/line/property/
Executing something in end element with attribute mandatory
/beanDescriptor/line/property/
Executing something in end element with some attribute with name mandatory and another with name page and value 4
/beanDescriptor/line/property/
Executing something in end element with some attribute with value pt
/beanDescriptor/line/property2/
Executing something in end element with attribute mandatory
/beanDescriptor/line/property2/
Executing something in end element with some attribute with value pt
Como você pode notar, cada método foi executado quando o elemento estava finalizando e quando o mesmo satisfazia as condições. Se você quiser colocar mais condições, você só precisaria colocar mais anotações do tipo ContainAttribute com duas propriedade desejadas. Ambos atributos do ContainAttribute, name e value, aceitam expressões regurares.
Se você reparar no resultado apresentado, existem métodos sendo executados devido ao mesmo elemento estar finalizando, já que as condição de todos foram satisfeitas, como, por exemplo, o elemento /beanDescriptor/line/property/. Nós não informamos o JColtrane sobre a ordem que desejamos fazer a execução, se mais de um método for executar. Suponhamos que você deseje executar os métodos nessa ordem: primeiro executeInEndElement3, depois executeInEndElement1 e depois executeInEndElement2. Você quer executar nessa ordem quando eles executarem no mesmo "tempo", ou seja, em nosso caso quando /beanDescriptor/line/property/ ou /beanDescriptor/line/property2/ estão finalizando. Façamos algumas mudanças em nossa classe para informar o JColtrane a ordem que desejamos:
public class EndElemetAction {
@EndElement(priority=2,attributes={@ContainAttribute(name="mandatory")})
public void executeInEndElement1(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in end element with attribute mandatory\n");
}
@EndElement(attributes={@ContainAttribute(name="mandatory"),@ContainAttribute(name="page",value="4")})
public void executeInEndElement2(@CurrentBranch String currentBranch){
System.out.println(currentBranch);
System.out.println("Executing something in end element with some attribute with name mandatory and another with name page and value 4\n");
}
@EndElement(priority=3,attributes={@ContainAttribute(value="pt")})
public void executeInEndElement3(@CurrentBranch String currentBrunch){
System.out.println(currentBranch);
System.out.println("Executing something in end element with some attribute with value pt\n");
}
}
Executando o teste com as mudanças, temos:
/beanDescriptor/line/property/
Executing something in end element with some attribute with value pt
/beanDescriptor/line/property/
Executing something in end element with attribute mandatory
/beanDescriptor/line/property/
Executing something in end element with some attribute with name mandatory and another with name page and value 4
/beanDescriptor/line/property2/
Executing something in end element with some attribute with value pt
/beanDescriptor/line/property2/
Executing something in end element with attribute mandatory
Como você pode ver, temos o resultado desejado usando a propriedade priority. Métodos anotados com maior priority serão executatos antes daqueles com menor priority.
JColtrane atribui valor de priority 0 (zero) por default. Essa é a razão pela qual não atribuimos ao método executeInEndElement2 um valor para priority e mesmo assim ele executou sempre depois dos demais métodos.
Resumimos todas as opções abaixo:
Opção |
Argumentos |
Significado |
tag |
regex |
elemento deve ter tag que é aceita pela expressão regular |
uri |
regex |
elemento deve ter uri que é aceita pela expressão regular |
localName |
regex |
elemento deve ter nome local que é aceito pela expressão regular |
priority |
int |
métodos com prioridades maiores serão executos antes, caso mais de um método seja executado no mesmo "momento" |
ContainAtribute |
( regex name , regex value ) |
o elemento deve conter um atributo reconhecido pela expressão regular de name e value |
Agora que você sabe as opções básicas, veja Outras Formas de Filtragem.