Avatar billede fredand Forsker
29. april 2022 - 21:04 Der er 8 kommentarer og
1 løsning

Create xml from two different xsd

Hello

I need to solve how to create a String of XML from two different xsd:s.

The result need to look like this snippet:

    <xsdone:Payloadinformation>
        <xsdone:Payload>
            <xsdtwo:AObjectElement xmlns:xsdtwo="com/company/xsdtwo/v1">
                <xsdtwo:ChildElementOne>123</xsdtwo:ChildElementOne>
                <xsdtwo:ChildElementTwo>ABC</xsdtwo:ChildElementTwo>
            </xsdtwo:AObjectElement>
        </xsdone:Payload>
    </xsdone:Payloadinformation>
   
The xsdone looks like this

      <xs:complexType name="PayloadinformationTYPE">
            <xs:sequence>
                  <xs:element name="Payload" type="xs:anyType" minOccurs="1" maxOccurs="1">
                  </xs:element>
            </xs:sequence>
      </xs:complexType>   
     
As you can see it uses xs:anyType

The xsdtwo looks like this

    <xs:complexType name="AObjectElementTYPE">
        <xs:sequence>
            <xs:element name="ChildElementOne" type="xs:int" minOccurs="1" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
   
To finally get the xml-string I use JaxB like:

    public static String getXmlStringForPayloadinformationTYPE(PayloadinformationTYPE payloadinformationTYPE) throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(PayloadinformationTYPE.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        // output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        JAXBElement<PayloadinformationTYPE> jaxbElement =
                new JAXBElement<>(new QName("", "xsdone:PayloadinformationTYPE"),
                                  PayloadinformationTYPE.class,
                                  payloadinformationTYPE);

        StringWriter lStringWriter = new StringWriter();
        jaxbMarshaller.marshal(jaxbElement, lStringWriter);
        return lStringWriter.toString();
    }
   
The problem might be in the above code, since it does not got any info about xsdtwo, I guess.
   
To set the Payload, the generated method in PayloadinformationTYPE looks like:
    public void setPayload( Object value )
As you can see it does not map to any xsd-generated class, just any instance of Object.

If I just create a AObjectElementTYPE and set it straight away as payload like

        AObjectElementTYPE aObjectElementTYPE = getAObjectElementTYPE();
        payloadinformationTYPE.setPayload(aObjectElementTYPE);

I get

  <xsdone:Payloadinformation>
      <xsdone:Payload>com.company.xsdtwo.v1.AObjectElementTYPE@cb0755b</xsdone:Payload>
     
As you see the payload is not as I expected.

I have also tried to set it like a String:
       
        AObjectElementTYPE aObjectElementTYPE = getAObjectElementTYPE();
        String lXmlStringForAObjectElementTYPE = getXmlStringForAObjectElementTYPE(aObjectElementTYPE); //This method looks in the same way as getXmlStringForPayloadinformationTYPE above
        payloadinformationTYPE.setPayload(lXmlStringForAObjectElementTYPE);
       
But then I get the xml like this:

    <xsdone:Payloadinformation>
          <xsdone:Payload xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>&#xd;
    &lt;AObjectElementTYPE xmlns=&quot;com/company/xsdbas/v1&quot; xmlns:xsdtwo=&quot;com/company/xsdtwo/v1&quot;>&#xd;
      &lt;xsdtwo:ChildElementOne>1&lt;/xsdtwo:ChildElementOne>&#xd;
    &lt;/AObjectElementTYPE>&#xd;
    </xsdone:Payload>
   
As you can see that is not what I excpected either.

My last, and best attempt so far is to

    AObjectElementTYPE aObjectElementTYPE = getAObjectElementTYPE();
    Node lXmlNodeForAObjectElementTYPE = getXmlNodeForAObjectElementTYPE(aObjectElementTYPE);
    payloadinformationTYPE.setPayload(lXmlNodeForAObjectElementTYPE);
   
    ...
   
    public static Node getXmlNodeForAObjectElementTYPE(AObjectElementTYPE aObjectElementTYPE) throws JAXBException, ParserConfigurationException, IOException, SAXException {
        JAXBContext jaxbContext = JAXBContext.newInstance(AObjectElementTYPE.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        // output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        JAXBElement<AObjectElementTYPE> jaxbElement =
                new JAXBElement<>(new QName("", "xsdtwo:AObjectElementTYPE"),
                                  AObjectElementTYPE.class,
                                  aObjectElementTYPE);

        StringWriter lStringWriter = new StringWriter();
        jaxbMarshaller.marshal(jaxbElement, lStringWriter);

        DocumentBuilderFactory lDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder lDocumentBuilder = lDocumentBuilderFactory.newDocumentBuilder();
        String lXmlString = lStringWriter.toString();
        lXmlString = lXmlString.substring( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n".length(),  lXmlString.length() );

        Element node =  DocumentBuilderFactory
                .newInstance()
                .newDocumentBuilder()
                .parse(new ByteArrayInputStream(lXmlString.getBytes()))
                .getDocumentElement();

        return node;
    }
   
    Then I get
      <xsdone:Payloadinformation>
      <AObjectElementTYPE xmlns="">
        <xsdtwo:ChildElementOne xmlns="">123</xsdtwo:ChildElementOne>
      </AObjectElementTYPE>
     
As you can see the tag Payload is missing and the value for attribute xmlns is missing?
The expected output should have been like:
   
      <xsdone:Payloadinformation>
        <xsdone:Payload>
            <xsdtwo:AObjectElement xmlns:xsdtwo="com/company/xsdtwo/v1">
            <xsdtwo:ChildElementOne>123</xsdtwo:ChildElementOne>
           
Do you guys got any better way to build the XML I need?
Best regards
Fredrik

PS I seem to forgot how to use bb-codes for code. I thought it was [code] ..[/code]
Avatar billede arne_v Ekspert
30. april 2022 - 02:07 #1
I did some experimentation.

Not totally there but some progress.

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:complexType name="PayloadinformationTYPE">
        <xs:sequence>
            <xs:element name="Payload" type="xs:anyType" minOccurs="1" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>


<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:complexType name="AObjectElementTYPE">
        <xs:sequence>
            <xs:element name="ChildElementOne" type="xs:int" minOccurs="1" maxOccurs="1"/>
            <xs:element name="ChildElementTwo" type="xs:string" minOccurs="1" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>


import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.namespace.QName;

import generated.AObjectElementTYPE;
import generated.PayloadinformationTYPE;

public class Test {
    public static class Container {
        private List<JAXBElement<?>> tags;
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Container(Object o, String tag) {
            this.tags = new ArrayList<>();
            tags.add(new JAXBElement(new QName(tag), o.getClass(), o));
        }
        @XmlAnyElement
        public List<JAXBElement<?>> getProperties() {
            return tags;
        }
        public void setProperties(List<JAXBElement<String>> properties) {
            throw new RuntimeException("Not implemented");
        }
    }
    public static void main(String[] args) throws JAXBException {
        AObjectElementTYPE aoet = new AObjectElementTYPE();
        aoet.setChildElementOne(123);
        aoet.setChildElementTwo("ABC");
        PayloadinformationTYPE plit = new PayloadinformationTYPE();
        plit.setPayload(new Container(aoet, "AObjectElement"));
        JAXBContext ctx = JAXBContext.newInstance(PayloadinformationTYPE.class, AObjectElementTYPE.class, Container.class);
        Marshaller m = ctx.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        JAXBElement<PayloadinformationTYPE> je = new JAXBElement<>(new QName("", "xsdone:PayloadinformationTYPE"), PayloadinformationTYPE.class, plit);
        StringWriter sw = new StringWriter();
        m.marshal(je, sw);
        System.out.print(sw.toString());
    }
}


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsdone:PayloadinformationTYPE>
    <Payload xsi:type="container" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <AObjectElement>
            <ChildElementOne>123</ChildElementOne>
            <ChildElementTwo>ABC</ChildElementTwo>
        </AObjectElement>
    </Payload>
</xsdone:PayloadinformationTYPE>
Avatar billede fredand Forsker
02. maj 2022 - 21:36 #2
Hello Arne,
Thanks for your effort, attempt and help!
I think this might be a away. Unfortenately we fail when the xml is procecessed since the Container class/xsd is not available.

Really tricky!
In our team some think we should do some string concat to solve it. I hope they will let me keep trying with your example tomorrow.
Best regards
Fredrik
Avatar billede arne_v Ekspert
03. maj 2022 - 01:50 #3
    @XmlType(name="xsd:anyType")
    public static class Container {
        private List<JAXBElement<?>> tags;
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Container(Object o, String tag) {
            this.tags = new ArrayList<>();
            tags.add(new JAXBElement(new QName(tag), o.getClass(), o));
        }
        @XmlAnyElement
        public List<JAXBElement<?>> getProperties() {
            return tags;
        }
        public void setProperties(List<JAXBElement<?>> tags) {
            throw new RuntimeException("Not implemented");
        }
    }


result in:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsdone:PayloadinformationTYPE>
    <Payload xsi:type="xsd:anyType" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <AObjectElement>
            <ChildElementOne>123</ChildElementOne>
            <ChildElementTwo>ABC</ChildElementTwo>
        </AObjectElement>
    </Payload>
</xsdone:PayloadinformationTYPE>


would that work?
Avatar billede fredand Forsker
03. maj 2022 - 09:11 #4
Hello
When I added @XmlType(name="xsd:anyType") ...sounded really resonable
We got the xml like:
...xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:anyType">
But then we got this Exception
UndeclaredPrefix: Cannot resolve 'xsd:anyType' as a QName: the prefix 'xsd' is not declared.

So it looks like we are missing the "xsd" declaration in some how.
I will see if I can find out how to add that.
To me it sounds that since the namespace/libary "xsd" is not present the type "anyType" is not availble.
Best regards
Fredrik
Avatar billede arne_v Ekspert
03. maj 2022 - 14:35 #5
That namespace is very standard.

Can it just be a xs vs xsd prefix problem so that it need to be xs:anyType?
Avatar billede fredand Forsker
03. maj 2022 - 15:15 #6
Hello Arne,
Thank you for that idea, I have also notice that xs or xsd is common (I really do not know why one of them is not enough). How ever I got the same exception.

UndeclaredPrefix: Cannot resolve 'xs:anyType' as a QName: the prefix 'xs' is not declared.

Best regards
/Fredrik
Avatar billede arne_v Ekspert
03. maj 2022 - 15:54 #7
    @XmlType(name="anyType", namespace="http://www.w3.org/2001/XMLSchema")
    public static class Container {
        private List<JAXBElement<?>> tags;
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public Container(Object o, String tag) {
            this.tags = new ArrayList<>();
            tags.add(new JAXBElement(new QName(tag), o.getClass(), o));
        }
        @XmlAnyElement
        public List<JAXBElement<?>> getProperties() {
            return tags;
        }
        public void setProperties(List<JAXBElement<?>> tags) {
            throw new RuntimeException("Not implemented");
        }
    }


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsdone:PayloadinformationTYPE>
    <Payload xsi:type="xs:anyType" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <AObjectElement>
            <ChildElementOne>123</ChildElementOne>
            <ChildElementTwo>ABC</ChildElementTwo>
        </AObjectElement>
    </Payload>
</xsdone:PayloadinformationTYPE>
Avatar billede fredand Forsker
03. maj 2022 - 17:21 #8
Hello Arne,

I think you solved it for me!!

How ever one odd, when I tried:

@XmlType(name="anyType", namespace="http://www.w3.org/2001/XMLSchema")

I got:
<Payload  xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:anyType">

...a bit different from yours xs and in my xsd

How ever I think this is a working solution!
Thanks alot!
Avatar billede arne_v Ekspert
03. maj 2022 - 17:42 #9
Mystisk men det betyder ikke noget.

xsi:type="xs:anyType" xmlns:xs="http://www.w3.org/2001/XMLSchema"

xsi:type="xsd:anyType" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xsi:type="foobar:anyType" xmlns:foobar="http://www.w3.org/2001/XMLSchema"

betyder det samme.

Forskellen skyldes formentlig forskellig JAXB library.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester