Como parsear tags com atributos e conteúdos usando XStream?

8 respostas
davidbuzatto

Olá pessoal, boa tarde.

Uso o XStream em alguns projetos, mas agora estou encontrando uma certa dificuldade.
Preciso converter uma hierarquia de objetos para uma determinada estrutura XML, sendo que esse XML contém tags do tipo:

<foo>
    <string language="pt">conteúdo... conteúdo... conteúdo...</string>
</foo>

Para isso, fiz o seguinte:

xstream.useAttributeFor( CharacterString.class, "language" ); 
xstream.registerConverter( new ConversorCharacterString() );

Sendo que a classe CharacterString gera a tag string e o campo language vira um atributo na tag. Para resolver o conteúdo, criei um conversor para CharacterString, que pega o conteúdo de um dos campos da classe e coloca como o corpo da tag string.

O problema é se as duas linhas acima são usadas juntas, o XStream só entende que quero colocar o conteúdo no corpo da tag string, não reconhecendo o atributo language.

Entenderam o que eu preciso? Gerar uma tag tanto com atributo quanto conteúdo.
Não estou conseguindo fazer isso, já olhei os tutoriais no site da XStream e ainda não consegui resolver.

Se alguém puder me ajudar, eu agradeço.

Seguem as listagens completas:

public class Foo {

    private CharacterString string;
   
    // gets e sets...

}

public class CharacterString {

    private String language;
    private String value;

    public CharacterString() {}

    public CharacterString( String value ) {
        setValue( value );
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

public class ConversorCharacterString implements SingleValueConverter {

    @Override
    public String toString( Object obj ) {
        return ( ( CharacterString ) obj ).getValue();
    }

    @Override
    public Object fromString( String value ) {
        return new CharacterString( value );
    }

    @Override
    public boolean canConvert( Class type ) {
        return type.equals( CharacterString.class );
    }

}

Muito obrigado.

[]´s

8 Respostas

fantomas

<foo> <string language="pt">conteúdo... conteúdo... conteúdo...</string> </foo>

Não sei se entendi direito…esta parte “conteúdo… conteúdo… conteúdo…” como que ela é realmente?

Vc pode modificar o exemplo?

flws

davidbuzatto
fantomas:
<foo>
    <string language="pt">conteúdo... conteúdo... conteúdo...</string>
</foo>

Não sei se entendi direito...esta parte "conteúdo... conteúdo... conteúdo..." como que ela é realmente?

Vc pode modificar o exemplo?

flws

Oi fantomas.

É conteúdo em texto. Por exemplo, um título:

<title>
    <string language="pt">Como trabalhar com XStream</string>
</title>

[]´s

fantomas

Você pode alterar a estrutura (incluir,alterar as tags) deste xml ou vc tem que se submeter a esta estrutura?

flws

davidbuzatto

fantomas:
Você pode alterar a estrutura (incluir,alterar as tags) deste xml ou vc tem que se submeter a esta estrutura?

flws

A estrutura é essa, não posso mexer. É uma especificação de metadados, tenho que usar da forma que está especificado…

[]´s

fantomas

Então...segue abaixo o código para ler o xml que vc colocou no post, espero que ajude:

Versão do XStream: xstream-1.3.jar

Xml: Alterei a tag para
<title>
    <description language="pt">Como trabalhar com XStream</description>
</title>

Codigo:

public class Application {
	
	public void run() {
		
		Title title = null;
		
		try {
			System.out.println("Inicio da leitura...");
			
			File file = new File("c://book.xml");
			
			title = this.loadXmlFile(file);
			
			System.out.println("Termino da leitura...");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private Title loadXmlFile(File file) throws Exception {
		XStream xstream = new XStream();

		xstream.registerConverter(new DescriptionConverter());
		
		xstream.alias("title", Title.class);
		
		FileReader reader = new FileReader(file);
			
		Title title = (Title) xstream.fromXML(reader);
		
		reader.close();
		
		return title;
	}
	
	public static void main(String[] args) {
		Application app = new Application();
		
		app.run();
	}
}
public class Title {
	private Description description = null;
	
	public Description getDescription() {
		return this.description;
	}
}
public class Description {
	private String language = null;
	private String name = null;
	
	public String getLanguage() {
		return language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
public class DescriptionConverter implements  Converter {

    public boolean canConvert(Class type) {
            return type.equals(Description.class);
    }

	public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext contex) {
	}

	public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
		
		Description description = new Description();

		description.setLanguage(reader.getAttribute("language"));
		description.setName(reader.getValue());
		
		reader.moveUp();
        
        return description;
	}
}

P.S Sempre garanta que o arquivo xml aberto e lido / escrito pelo xstream seja fechado ao termino do processamento, me parece que ele não fecha pra vc logo fique atento a este detalhe.

flws

davidbuzatto

Oi fantomas, muito obrigado. Vou testar agora e já posto se funcionou.

Na verdade eu só vou precisar gerar o xml. É para o meu projeto de mestrado :wink:

[]´s

fantomas

Neste caso vc terá que dar uma atenção especial ao metodo
marshal da classe DescriptionConverter porque é ele que cuida da parte escrita do xml.

P.S Achei que vc estava penas querendo ler o arquivo.

flws

davidbuzatto

Muito bom fantomas, funcionou. Só preisei implementar o método marshal.
Ficou assim.

public class LangStringConverter implements Converter {

    @Override
    public boolean canConvert(Class type) {
        return type.equals(LangString.class);
    }

    @Override
    public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext contex) {

        LangString langString = ( LangString ) o;

        writer.addAttribute( "language", langString.getLanguage() );
        writer.setValue( langString.getValue() );

    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {

        LangString langString = new LangString();

        langString.setLanguage(reader.getAttribute("language"));
        langString.setValue(reader.getValue());

        reader.moveUp();

        return langString;
    }
    
}
Criado 2 de junho de 2009
Ultima resposta 3 de jun. de 2009
Respostas 8
Participantes 2