Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write namespace declaration on root element only? #670

Open
carlanton opened this issue Sep 11, 2024 · 4 comments
Open

Write namespace declaration on root element only? #670

carlanton opened this issue Sep 11, 2024 · 4 comments

Comments

@carlanton
Copy link

carlanton commented Sep 11, 2024

Hello and thank you for such an awesome project!

I'm using dataformat-xml to create a video manifest (MPEG-DASH mpd), and for aesthetic reasons I'd really like if it could write all namespace declarations on the root element.

The XML I generate currently looks like this:

<MPD xmlns="urn:mpeg:dash:schema:mpd:2011"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd">
  <ContentProtection value="ClearKey1.0" schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e">
    <dashif:Laurl xmlns:dashif="https://dashif.org/guidelines/clearKey">https://example.com/license</dashif:Laurl>
  </ContentProtection>
</MPD>

but I want to move the "xmlns:dashif="https://dashif.org/guidelines/clearKey"" to . Like this:

<MPD xmlns="urn:mpeg:dash:schema:mpd:2011"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd"
     xmlns:dashif="https://dashif.org/guidelines/clearKey">
  <ContentProtection value="ClearKey1.0" schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e">
    <dashif:Laurl>https://example.com/license</dashif:Laurl>
  </ContentProtection>
</MPD>

Is it possible to configure / override something in XmlMapper or Woodstox to make this work?

Thanks a lot,
Anton

Java 21 with com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2

@carlanton
Copy link
Author

Currently I'm doing something like this to deserialize and serialize the video manifest but I get the xmlns:dashif thing on dashif:Laurl.

package io.lindstrom.mpd;

import com.ctc.wstx.api.WriterConfig;
import com.ctc.wstx.stax.WstxInputFactory;
import com.ctc.wstx.stax.WstxOutputFactory;
import com.ctc.wstx.sw.XmlWriter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.codehaus.stax2.XMLStreamWriter2;
import org.junit.jupiter.api.Test;

import javax.xml.stream.XMLOutputFactory;

public class GhIssue {

    @JacksonXmlRootElement(localName = "MPD", namespace = "urn:mpeg:dash:schema:mpd:2011")
    private static class MPD {
        @JacksonXmlProperty(isAttribute = true, namespace = "http://www.w3.org/2001/XMLSchema-instance")
        private String schemaLocation;

        @JacksonXmlProperty(localName = "ContentProtection", namespace = "urn:mpeg:dash:schema:mpd:2011")
        private ContentProtection contentProtection;
    }

    private static class ContentProtection {
        @JacksonXmlProperty(isAttribute = true)
        private String value;

        @JacksonXmlProperty(isAttribute = true)
        private String schemeIdUri;

        @JacksonXmlProperty(localName = "Laurl", namespace = "https://dashif.org/guidelines/clearKey")
        private String laurl;
    }


    @Test
    void demo() throws JsonProcessingException {
        String input = """
                <MPD xmlns="urn:mpeg:dash:schema:mpd:2011"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd">
                     <ContentProtection xmlns:dashif="https://dashif.org/guidelines/clearKey"
                         value="ClearKey1.0" schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e">
                            <dashif:Laurl>https://example.com/license</dashif:Laurl>
                    </ContentProtection>
                </MPD>
                """;

        XMLOutputFactory xmlOutputFactory = new WstxOutputFactory() {
            @Override
            protected XMLStreamWriter2 createSW(String enc, WriterConfig cfg, XmlWriter xw) {
                XMLStreamWriter2 streamWriter = super.createSW(enc, cfg, xw);
                try {
                    streamWriter.setPrefix("xsi", "http://www.w3.org/2001/XMLSchema-instance");
                    streamWriter.setPrefix("dashif", "https://dashif.org/guidelines/clearKey");
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return streamWriter;
            }
        };

        ObjectMapper xmlMapper = new XmlMapper(new XmlFactory(new WstxInputFactory(), xmlOutputFactory));
        MPD mpd = xmlMapper.readValue(input, MPD.class);

        String out = xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(mpd);
        System.out.println(out);
    }
}

@cowtowncoder
Copy link
Member

(note: similar to #666)

So, the short answer is that this might be possible by pre-constructing XMLStreamWriter via Woodstox, and I think there's a way to bind namespace URI/prefix... but not 100% sure there's a way to force writing of namespace except by XMLStreamWriter.writeNamespace(...)... doing which actually would require outputting root element.

Hmmh. So this might not be doable as things are.

But maybe there'd be need for additional handler, to be called right after outputting starting root element -- at which point it's possible to write namespace declarations (as well as possible XML attributes).

I can leave this issue open for adding ability to register such handler.

@carlanton carlanton changed the title Write namespace decleration on root element only? Write namespace declaration on root element only? Sep 11, 2024
@slusset
Copy link

slusset commented Sep 30, 2024

Even if all elements are in the same namespace is it required to declare namespace on each field? Currently that is what I have to do, e.g.

@JacksonXmlRootElement(namespace = "mynamespace")
public record RxUpdate(

  @JacksonXmlProperty(localName = "EventName", namespace = "mynamespace")
  String EventName,

  @JacksonXmlProperty(localName = "NCPDP", namespace = "mynamespace")
  String NCPDP

@cowtowncoder
Copy link
Member

@slusset Yes, there is unfortunately no implied inheritance of namespace information on Java model side, for Jackson.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants