te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>java - Maintain Order Of Sibling Tags When Creating XML Using JAXB Marshaller - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Maintain Order Of Sibling Tags When Creating XML Using JAXB Marshaller - Stack Overflow

programmeradmin4浏览0评论

I have an XML like the following.

<Transactions>
  <FileHeader>
    <!--SOME VALUES-->
  </FileHeader>
  <BatchHeader>
    <!--SOME VALUES-->
  </BatchHeader>
  <Entry>
    <!--SOME VALUES-->
  </Entry>
  <Addenda>
    <!--SOME VALUES-->
  </Addenda>
  <Entry>
    <!--SOME VALUES-->
  </Entry>
  <Addenda>
    <!--SOME VALUES-->
  </Addenda>
  <BatchControl>
    <!--SOME VALUES-->
  </BatchControl>
  <BatchHeader>
    <!--SOME VALUES-->
  </BatchHeader>
  <Entry>
    <!--SOME VALUES-->
  </Entry>
  <Addenda>
    <!--SOME VALUES-->
  </Addenda>
  <BatchControl>
    <!--SOME VALUES-->
  </BatchControl>
  <FileControl>
    <!--SOME VALUES-->
  </FileControl>
</Transactions>

Essentially, except FileHeader and FileControl all are lists. I am parsing (unmarshalling) the xml using JAXB, with the following defined objects:

    @Getter @Setter
    @XmlRootElement(name = "Transactions")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Transactions {
        @XmlElement(name = "FileHeader")
        private FileHeader fileHeader;

        @XmlElement(name = "BatchHeader")
        private List<BatchHeader> batchHeaderList;

        @XmlElement(name = "Entry")
        private List<Entry> entryList;

        @XmlElement(name = "Addenda")
        private List<Addenda> addendaList;

        @XmlElement(name = "BatchControl")
        private List<BatchControl> batchControl;

        @XmlElement(name = "FileControl")
        private FileControl fileControl;
    }

Now the marshalling works well. The order of the tags are maintained, that is the BatchHeader at index x corresponds with BatchControl at index x.

But while unmarshalling all the BatchHeader comes first, then all Entries, then Addendum and so on. With my experience so far with JAXB, I understand this is the logical behavior however, not my desired behavior. I want the xml to be in exact order as it was originally, that is BatchHeader 1, then the Entries and Addedum for it, then BatchControl 1, then BatchHeader 2 and so on.

I tried with @XmlType(propOrder={}) but realized it's not for my exact purpose. I looked up in the internet but did not find much. Online LLM models were no help whatsoever.

Is is possible with JAXB ? and If so how ? Currently I have resorted to the manual approach of painfully adding each data to a StringBuilder and then creating the xml.

I have an XML like the following.

<Transactions>
  <FileHeader>
    <!--SOME VALUES-->
  </FileHeader>
  <BatchHeader>
    <!--SOME VALUES-->
  </BatchHeader>
  <Entry>
    <!--SOME VALUES-->
  </Entry>
  <Addenda>
    <!--SOME VALUES-->
  </Addenda>
  <Entry>
    <!--SOME VALUES-->
  </Entry>
  <Addenda>
    <!--SOME VALUES-->
  </Addenda>
  <BatchControl>
    <!--SOME VALUES-->
  </BatchControl>
  <BatchHeader>
    <!--SOME VALUES-->
  </BatchHeader>
  <Entry>
    <!--SOME VALUES-->
  </Entry>
  <Addenda>
    <!--SOME VALUES-->
  </Addenda>
  <BatchControl>
    <!--SOME VALUES-->
  </BatchControl>
  <FileControl>
    <!--SOME VALUES-->
  </FileControl>
</Transactions>

Essentially, except FileHeader and FileControl all are lists. I am parsing (unmarshalling) the xml using JAXB, with the following defined objects:

    @Getter @Setter
    @XmlRootElement(name = "Transactions")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Transactions {
        @XmlElement(name = "FileHeader")
        private FileHeader fileHeader;

        @XmlElement(name = "BatchHeader")
        private List<BatchHeader> batchHeaderList;

        @XmlElement(name = "Entry")
        private List<Entry> entryList;

        @XmlElement(name = "Addenda")
        private List<Addenda> addendaList;

        @XmlElement(name = "BatchControl")
        private List<BatchControl> batchControl;

        @XmlElement(name = "FileControl")
        private FileControl fileControl;
    }

Now the marshalling works well. The order of the tags are maintained, that is the BatchHeader at index x corresponds with BatchControl at index x.

But while unmarshalling all the BatchHeader comes first, then all Entries, then Addendum and so on. With my experience so far with JAXB, I understand this is the logical behavior however, not my desired behavior. I want the xml to be in exact order as it was originally, that is BatchHeader 1, then the Entries and Addedum for it, then BatchControl 1, then BatchHeader 2 and so on.

I tried with @XmlType(propOrder={}) but realized it's not for my exact purpose. I looked up in the internet but did not find much. Online LLM models were no help whatsoever.

Is is possible with JAXB ? and If so how ? Currently I have resorted to the manual approach of painfully adding each data to a StringBuilder and then creating the xml.

Share Improve this question edited yesterday ShahriyarHossain asked 2 days ago ShahriyarHossainShahriyarHossain 801 silver badge8 bronze badges 1
  • Marshaling is probably following the order within the list so a LinkedHashSet would be advisable. – LMC Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 0

I have not tested this but here's a design that groups the related quartet (Addenda, BatchControl, BatchHeader, Entry) into a choice element. The choice element allows for a heterogeneous list of sub-elements. The order in the choice does not matter (to JAXB); but, I believe JAXB will honor the order of the elements during unmarshaling and again during marshaling.

Transactions.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3./2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="Transactions">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="FileHeader"/>
        <xs:choice maxOccurs="unbounded">
          <xs:element ref="Addenda"/>
          <xs:element ref="BatchControl"/>
          <xs:element ref="BatchHeader"/>
          <xs:element ref="Entry"/>
        </xs:choice>
        <xs:element ref="FileControl"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="FileHeader">
    <xs:complexType/>
  </xs:element>
  <xs:element name="Addenda">
    <xs:complexType/>
  </xs:element>
  <xs:element name="BatchControl">
    <xs:complexType/>
  </xs:element>
  <xs:element name="BatchHeader">
    <xs:complexType/>
  </xs:element>
  <xs:element name="Entry">
    <xs:complexType/>
  </xs:element>
  <xs:element name="FileControl">
    <xs:complexType/>
  </xs:element>
</xs:schema>

Using XJC to generate the Java classes produces this set:

XJC Generated Classes

Addenda.java
BatchControl.java
BatchHeader.java
Entry.java
FileControl.java
FileHeader.java
ObjectFactory.java
Transactions.java

For the simple XML example given, only the Transactions class is interesting. It declares a propOrder for fileHeader, addendaOrBatchControlOrBatchHeader, and fileControl to keep the general ordering in line. The addendaOrBatchControlOrBatchHeader represents the choice structure and it holds the unmarshalled elements from the quartet in order.

The main take away is that you need to express the cardinality in some way that preserves order and choice is one option.

Transactions.java

// This file was generated by the Eclipse Implementation of JAXB, v4.0.5 

package generated;

import java.util.ArrayList;
import java.util.List;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElements;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "fileHeader",
    "addendaOrBatchControlOrBatchHeader",
    "fileControl"
})
@XmlRootElement(name = "Transactions")
public class Transactions {

    @XmlElement(name = "FileHeader", required = true)
    protected FileHeader fileHeader;
    @XmlElements({
        @XmlElement(name = "Addenda", type = Addenda.class),
        @XmlElement(name = "BatchControl", type = BatchControl.class),
        @XmlElement(name = "BatchHeader", type = BatchHeader.class),
        @XmlElement(name = "Entry", type = Entry.class)
    })
    protected List<Object> addendaOrBatchControlOrBatchHeader;
    @XmlElement(name = "FileControl", required = true)
    protected FileControl fileControl;

    public FileHeader getFileHeader() {
        return fileHeader;
    }

    public void setFileHeader(FileHeader value) {
        this.fileHeader = value;
    }

    public List<Object> getAddendaOrBatchControlOrBatchHeader() {
        if (addendaOrBatchControlOrBatchHeader == null) {
            addendaOrBatchControlOrBatchHeader = new ArrayList<>();
        }
        return this.addendaOrBatchControlOrBatchHeader;
    }

    public FileControl getFileControl() {
        return fileControl;
    }

    public void setFileControl(FileControl value) {
        this.fileControl = value;
    }
}
发布评论

评论列表(0)

  1. 暂无评论