Jaxb 使用保留原始命名空间前缀对 xml 的各个部分进行编组

Jaxb marshalling parts of xml with keeping original namespacess prefix

提问人:Frankio1 提问时间:3/30/2022 最后编辑:Frankio1 更新时间:4/3/2022 访问量:465

问:

我正在使用下面的插件来生成 jaxb 类。然后,我从文件系统中读取一些 XML,并将其解组为生成的 jaxb 类。这些类有条目的集合,我需要单独解组,做一些业务逻辑,并为每个部分解组并将它们存储为 xml 部分。所以实际上我正在做 XML -> Object(做一些业务逻辑)->我存储在某处的较小 XML。问题在于文件系统中的 XML 具有正确的命名空间前缀(如 tca、tcb、tcc),并且在将这些较小的部分编组回 xml 时,jaxb 会创建自己的命名空间前缀,如 ns1、ns2、ns3。是否可以像原始文件一样拥有 tca、tcb、tcc?但也许不要定义我自己的前缀映射,因为我永远不知道我的文件系统会出现什么前缀。一些外部方将来可能会更改它们,我只想保留原始的。贝洛是我的代码。

代码生成插件:

<plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>${jaxb2-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sources>
                        <source>src/main/resources/my.xsd</source>
                    </sources>
                    <outputDirectory>${basedir}/target/generated-sources/java</outputDirectory>
                    <clearOutputDir>false</clearOutputDir>
                </configuration>
            </plugin>

代码

        JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);

        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        while (streamReader.hasNext()) {
            if (streamReader.isStartElement()) {
                if (streamReader.getName() != null && streamReader.getName().getLocalPart() != null) {
                    String localPart = streamReader.getName().getLocalPart();
                    if (localPart.equalsIgnoreCase(XmlElements.CAR)) {
                        JAXBElement<Car> carJAXBElement = unmarshaller.unmarshal(streamReader, Car.class);
                        //doing some business logic 
                        JAXBContext context = JAXBContext.newInstance(Car.class);
                        Marshaller m = context.createMarshaller();
                        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                        StringWriter sw = new StringWriter();
                        m.marshal(carJAXBElement, sw);
                        String result = sw.toString();  //the result has namespaces prefixes changed
                        //and then saving one car xml part somewhere
                       
                    }
                }
            }
            streamReader.next();

xml 文件

原始文件:

<?xml version="1.0" encoding="UTF-8"?>
<tca:myroot xmlns:tca="http://myspec/tca/1.0" >
    <tca:car>
        <tca:owner>
            <tca:name>
            </tca:name>
        </tca:owner>
    </tca:car>
    <tca:car>
        <tca:owner>
            <tca:name>
            </tca:name>
        </tca:owner>
    </tca:car>
</tca:myroot>

编组的汽车 xml 部分:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:car xmlns:ns4="http://myspec/tca/1.0" >
    <ns4:owner>
        <ns4:name>
        </ns4:name>
    </ns4:owner>
</ns4:car>

编组后,是否可以在这些小型汽车零件中具有原始命名空间前缀?

Java XML XML 解析 JAXB 编组

评论


答:

0赞 Frankio1 4/3/2022 #1

所以尽管没有答案,我自己想通了。因此,我正在为未来的搜索者添加信息 - 如果您觉得我的答案有用,请将我的答案标记为有效,因为我不想自己做。

我使用了 NamespacePrefixMapper,其中我为从其第一个元素读取的 xml 文件中的每个命名空间提供了映射前缀 -> 命名空间 uri。它工作正常,但 Sonar 抱怨我正在使用 sun 内部类:

 JAXBContext context = JAXBContext.newInstance(clazz);
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper(namespaces));

所以我然后使用了package-info.java方法。我注意到,该目标创建了默认的包信息.java。在此文件中,可以将您自己的命名空间前缀添加到命名空间 uri 映射中。然后,我曾经将我自己的package-info.java复制到生成的类包中。最后,当编组器将对象转换回 xml 文件时,它使用我的 package-info.java 并保留原始命名空间前缀而不是 ns1、ns2 等。jaxb2-maven-pluginxjcmaven-resources-plugin

<plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <overwrite>true</overwrite>
                            <outputDirectory>${basedir}/target/generated-sources/java/package_where_default_package_info_is_generated</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>${basedir}/src/main/resources/bindings</directory>
                                    <include>package-info.java</include>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>