Solved

Xml to Java Using Xstream (attribute issue)

Posted on 2010-09-23
24
840 Views
Last Modified: 2012-05-10
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

0
Comment
Question by:jaypi
  • 14
  • 10
24 Comments
 
LVL 16

Expert Comment

by:Valeri
ID: 33745752
0
 

Author Comment

by:jaypi
ID: 33745786
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33745969
try with
xstream.aliasField("Name", Name.class, "value");
instead of
String fluxXml = "<Name id=\"1\">John</Name>";
0
How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

 
LVL 16

Expert Comment

by:Valeri
ID: 33745992
I mean before :-)
String fluxXml = "<Name id=\"1\">John</Name>";
0
 

Author Comment

by:jaypi
ID: 33746072
Doesn't work:

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

1
null
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33746305
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
 

Author Comment

by:jaypi
ID: 33746402
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33747400
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
 

Author Comment

by:jaypi
ID: 33747572
You are wrong, this XML is perfectly valid.

Check it here: http://www.w3schools.com/XML/xml_validator.asp
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33748610
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
 

Author Comment

by:jaypi
ID: 33748662
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33748729
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
 

Author Comment

by:jaypi
ID: 33748762
I can't believe that Xstream can't take such a basic XML... :(
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33748913
It can, but you need more code to do that... I'll try to send you this code...
0
 
LVL 16

Expert Comment

by:Valeri
ID: 33749316
You have to use single tag convertors. See the attached files.
Name.java
NameConverter.java
0
 

Author Comment

by:jaypi
ID: 33749347
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33751796
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33751832
...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
 

Author Comment

by:jaypi
ID: 33751849
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33751914
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
 

Author Comment

by:jaypi
ID: 33751928
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
 
LVL 16

Expert Comment

by:Valeri
ID: 33752012
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
 
LVL 16

Accepted Solution

by:
Valeri earned 500 total points
ID: 33763311
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
 

Author Comment

by:jaypi
ID: 33764211
Hi Valeri,

you finally found the best solution. Well done!
0

Featured Post

MIM Survival Guide for Service Desk Managers

Major incidents can send mastered service desk processes into disorder. Systems and tools produce the data needed to resolve these incidents, but your challenge is getting that information to the right people fast. Check out the Survival Guide and begin bringing order to chaos.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
The Problem How to write an Xquery that works like a SQL outer join, providing placeholders for absent data on the outer side?  I give a bit more background at the end. The situation expressed as relational data Let’s work through this.  I’ve …
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:

679 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question