0

I want deserialize below xml

<Test>
    <message num="90">[WANT TO EXTRACT THIS DATA]
        <care>test data 1</care>
        <care>test data 2</care>
    </message>
</Test>

Having structure like below

@JacksonXmlRootElement(localName = "Test")
public class Policy {

    @JacksonXmlProperty(localName = "message ")
    private final Message message;
//builders
}

In message class I having like below

public class Message{

    @JacksonXmlProperty(localName = "care")
    private final List<String> care;

//builders
}

Now I want to extract this [WANT TO EXTRACT THIS DATA] value, which has no tags. Please help me to resolve this

Remo
  • 534
  • 7
  • 26
  • Duplicate of [(De)Serialize mixed content with jackson xml?](https://stackoverflow.com/q/43531284/5221149), saying "no solution". --- JAXB can do it, though. – Andreas Apr 13 '20 at 11:57
  • Your mentioned question has tag with mixed tags. But for my case I have this after element "[WANT TO EXTRACT THIS DATA]". Is both questions are same? Don't jackson have any other option to deal this? – Remo Apr 13 '20 at 12:09
  • `[WANT TO EXTRACT THIS DATA]` is not an element, it is **text**, which means that the content of `` consists of a *mixture* of text and elements. The XML terminology for that is **mixed content**. See section [3.2.2 Mixed Content](https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-mixed-content) of the [**Extensible Markup Language (XML) 1.1 (Second Edition) Specification**](https://www.w3.org/TR/2006/REC-xml11-20060816/). – Andreas Apr 13 '20 at 12:16
  • got it. Is custom jackson deserializer also not work for this case? – Remo Apr 13 '20 at 12:21

1 Answers1

0

You can do it with JAXB like this:

@XmlRootElement(name = "Test")
class Policy {
    private Message message;

    public Message getMessage() {
        return this.message;
    }
    public void setMessage(Message message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "Policy [message=" + this.message + "]";
    }
}
public class Message {
    private int num;
    private List<Object> content;

    @XmlAttribute
    public int getNum() {
        return this.num;
    }
    public void setNum(int num) {
        this.num = num;
    }

    @XmlMixed
    @XmlElementRefs({
        @XmlElementRef(name="care", type=Care.class)})
    public List<Object> getContent() {
        return this.content;
    }
    public void setContent(List<Object> content) {
        this.content = content;
    }

    @XmlTransient
    public String getText() {
        if (this.content == null)
            return null;
        StringBuilder text = new StringBuilder();
        for (Object obj : this.content)
            if (obj instanceof String)
                text.append(obj);
        return text.toString().trim();
    }

    @XmlTransient
    public List<String> getCare() {
        if (this.content == null)
            return null;
        List<String> care = new ArrayList<>();
        for (Object obj : this.content)
            if (obj instanceof Care)
                care.add(((Care) obj).getValue());
        return care;
    }

    @Override
    public String toString() {
        return "Message[num=" + this.num + ", content=" + this.content + "]";
    }
}
@XmlRootElement(name = "care")
public class Care {
    private String value;

    @XmlValue
    public String getValue() {
        return this.value;
    }
    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Care[value=" + this.value + "]";
    }
}

Test

String input = "<Test>\r\n" + 
               "    <message num=\"90\">[WANT TO EXTRACT THIS DATA]\r\n" + 
               "        <care>test data 1</care>\r\n" + 
               "        <care>test data 2</care>\r\n" + 
               "    </message>\r\n" + 
               "</Test>";
JAXBContext jaxbContext = JAXBContext.newInstance(Policy.class, Care.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Policy policy = (Policy) unmarshaller.unmarshal(new StringReader(input));
System.out.println(policy);
System.out.println("text = \"" + policy.getMessage().getText().replace("\n", "\\n") + "\"");
System.out.println("care = " + policy.getMessage().getCare());

Output

Policy [message=Message[num=90, content=[[WANT TO EXTRACT THIS DATA]
        , Care[value=test data 1], 
        , Care[value=test data 2], 
    ]]]
text = "[WANT TO EXTRACT THIS DATA]"
care = [test data 1, test data 2]
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • @JacksonXmlProperty(localName = "care") @JacksonXmlElementWrapper(useWrapping = false) private final List care; this is deserialize the List. Is any way to mix jackson and jaxb? – Remo Apr 13 '20 at 13:53
  • @Bharathi No, they are competing implementations of XML (de)serializers. – Andreas Apr 13 '20 at 20:13
  • I tried this code, but got care list all values as null. Also want to use jaxb with builder class – Remo Apr 19 '20 at 02:03
  • @Bharathi The output shown here is from running the exact code shown here, so if you get `null` values, then you did something different. Don't know what "jaxb with builder class" means. – Andreas Apr 19 '20 at 04:09
  • builder class means, here we have used setters and getters. But how to deserialize with builder pattern(Immutable class) – Remo Apr 19 '20 at 04:55
  • @Bharathi You can't, not using JAXB, since it is for (un)marshaling from/to POJOs. --- Now, if you want immutable class without using builder, you can make the fields non-final, and annotate the class with `@XmlAccessorType(XmlAccessType.FIELD)` or with `NONE`, and put all the other `@Xml...` annotations on the fields, so JAXB uses reflection to assign the fields directly. --- Alternatively, consider the POJOs to be your builder classes, and have them create the immutable classes after JAXB is done. If you want help with that, ask a new question. *This* question has been answered!! – Andreas Apr 19 '20 at 05:07
  • I didn't get last sentence, Is it possible to give the example for that in same code which you answered? – Remo Apr 19 '20 at 05:14
  • @Bharathi *This* question was not about using builder pattern, it was about **mixed content**, and that has been answered. If you have question about how to use builder pattern with JAXB, then create a new question asking about that. StackOverflow is about building a repository of answers/solutions, and needs to keep *one question per question*, so the relevant questions are easy to find, and people won't have to read through a lot of irrelevant information to their issue. --- Question about mixed content and question about builders are both good, but they are 2 separate questions. – Andreas Apr 19 '20 at 05:18
  • I have already "https://stackoverflow.com/questions/61289029/how-to-deserialize-xml-with-both-jackson-and-jaxb-using-builder-class" question with detailed builder class which I used. Do you have any idea? – Remo Apr 19 '20 at 05:26