Xml to Java Using Xstream (attribute issue)

Hi,

I'm using Xstream 1.2.1 and I'm trying to convert this XML

<Name id="1">John</Name>

Into a Java Object.

Here's the "Name" class and my code.

The result is :
1
null
public class Name{
		private String id ="";
		private String value = "";
		public String getId() {
			return id;
		}
		public void setId(String pId) {
			id = pId;
		}
		public String getValue() {
			return value;
		}
		public void setValue(String pValue) {
			value = pValue;
		}
	}

Open in new window

XStream xstream = new XStream();
		xstream.alias("Name", Name.class);
		xstream.useAttributeFor("id", String.class);
		String fluxXml = "<Name id=\"1\">John</Name>";
		Name name = (Name)xstream.fromXML(fluxXml);
		System.out.println(name.getId());
		System.out.println(name.getValue());

Open in new window

jaypiAsked:
Who is Participating?
 
ValeriConnect With a Mentor Commented:
Hi jaypi,
I've been thinking about your issue, you can write only one converter that converts a lot of tags like that:
<Name id="5">John</Name>
See the attached file. With one converter you can convert different types of tag.
I think that this is the best solution for you.
TagConverter.java
0
 
ValeriCommented:
0
 
jaypiAuthor Commented:
It's not the same. In the link you sent, the solution describes how to convert from an Object to XML :

System.out.println(xStreamObj.toXML(g));

I need to do the opposite.

Mapping :

<Name id="1">John</Name>

to an Object
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
ValeriCommented:
try with
xstream.aliasField("Name", Name.class, "value");
instead of
String fluxXml = "<Name id=\"1\">John</Name>";
0
 
ValeriCommented:
I mean before :-)
String fluxXml = "<Name id=\"1\">John</Name>";
0
 
jaypiAuthor Commented:
Doesn't work:

System.out.println(name.getId());
System.out.println(name.getValue());

1
null
0
 
ValeriCommented:
wow?!
I think that in your class 'value' must be replaced with 'name'
public class Name{
            private String id ="";
            private String name = "";
            public String getId() {
                  return id;
            }
            public void setId(String pId) {
                  id = pId;
            }
            public String getName() {
                  return name;
            }
            public void setName(String pName) {
                  name = pName;
            }
      }
0
 
jaypiAuthor Commented:
Not good

Here's a recap :

      public class Name{
            private String id ="";
            private String name = "";
            public String getId() {
                  return id;
            }
            public void setId(String pId) {
                  id = pId;
            }
            public String getName() {
                  return name;
            }
            public void setName(String pName) {
                  name = pName;
            }

            XStream xstream = new XStream();
            xstream.alias("Name", Name.class);
            xstream.useAttributeFor("id", String.class);
            xstream.aliasField("name", Name.class, "value");
            String fluxXml = "<Name id=\"1\">John</Name>";
            Name name = (Name)xstream.fromXML(fluxXml);
            System.out.println(name.getId());
            System.out.println(name.getName());
            System.out.println(xstream.toXML(name));

Output :
1
null
<Name id="1"/>
0
 
ValeriCommented:
Actually I was wrong, because you can't proceed in this way.
<Name id="1">John</Name> is not valid xml.
I think that in order to parse it with the original class from your question it should be something like that:
<Name id="1">
   <value>John</value>
</Name>
0
 
jaypiAuthor Commented:
You are wrong, this XML is perfectly valid.

Check it here: http://www.w3schools.com/XML/xml_validator.asp
0
 
ValeriCommented:
tag Name is mapped to Name.class, attribute id is mapped to member id, but to member name nothing is mapped... that's way you need tag in order to have this mapping too. This works :
import com.thoughtworks.xstream.XStream;

public class Name {
    private String id = "";
    private String name = "";

    public Name(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
          return id;
    }
    public void setId(String pId) {
          id = pId;
    }
    public String getName() {
          return name;
    }
    public void setName(String name) {
          this.name = name;
    }
    public static void main(String[] args) {
        XStream xstream = new XStream();
        xstream.alias("Name", Name.class);
        xstream.useAttributeFor("id", String.class);
        String fluxXml = "<Name id=\"5\"><name>John</name></Name>";
        Name name = (Name)xstream.fromXML(fluxXml);
        System.out.println(name.getId());
        System.out.println(name.getName());

        Name name2 = new Name("7", "Peter");
        System.out.println(xstream.toXML(name2));
    }
}
0
 
jaypiAuthor Commented:
I can't decide on the format of the XML, so I can't use that:

<Name id="5"><name>John</name></Name>

I need to know if there's a way mapping this:

<Name id="5">John</Name>
0
 
ValeriCommented:
This is because this is a library for serialization from xml to objects and from objects to xml, and each tag from xml must correspond to the respective member of the class...
0
 
jaypiAuthor Commented:
I can't believe that Xstream can't take such a basic XML... :(
0
 
ValeriCommented:
It can, but you need more code to do that... I'll try to send you this code...
0
 
ValeriCommented:
You have to use single tag convertors. See the attached files.
Name.java
NameConverter.java
0
 
jaypiAuthor Commented:
Thanks for this code, but the example is really an easy case:

In reality, the xml to convert is much more bigger:

<request>
<name id="1">John</name>
<adress>
<street number="21">Street name</street>
<city zip="123">Gotham City</city>
</adress>
...
</request>

It's a bit tedious to create a converter for each tag...
0
 
ValeriCommented:
There is no way to avoid the converter in this case. The only way to avoid converter is to use the following format:
<Name id="5">
<name>John</name></Name>
0
 
ValeriCommented:
...but you told me that you can't change the format of the xml, so you have to use the converter. Take a look at interface HierarchicalStreamReader, there is getValue() method and in your case this is the only way to set this value to the member "value" from your class. There is no other way for mapping.
If you don't want to write converters, then yuou have to ask the producer of the xml to change the xml like that:
<Name>
  <id>5</id>
  <value>John</value>
</Name>
0
 
jaypiAuthor Commented:
Thanks for your update Valeri.

I'm going to try another solution: transforming the xml with xsl

Input:
<test id="1">bla</test>

output:
<test>
 <id>1</id>
 <test>bla</test>
</test>

Don't see other solutions... Writing 15 converters... Not funny :D
0
 
ValeriCommented:
Yes, may be it's the best solution in your case!
Other solution is to parse this XML by yourself withg SAX let say, and to produce the objects as you want.
Good luck!
0
 
jaypiAuthor Commented:
Here's the XSL to create an Xstream friendly XML:

Thanks to Gertone for that.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="*[string-length(normalize-space(text())) > 0][@*]">
        <xsl:copy>
            <xsl:for-each select="@*">
                <xsl:element name="{name()}">
                    <xsl:value-of select="."/>
                </xsl:element>
            </xsl:for-each>
            <xsl:element name="{name()}">
                <xsl:apply-templates select="node()"/>
            </xsl:element>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node()">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Open in new window

0
 
ValeriCommented:
Looks good! I've never been so good in XSL transformations! :-)
If you don't need to transfer your objects back to the same xml later, I think that this is a good solution for you.
0
 
jaypiAuthor Commented:
Hi Valeri,

you finally found the best solution. Well done!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.