使用 DSM(声明性流映射)将 XML 文件解组为对象
Unmarshall XML file to Object with DSM (Declarative Stream Mapping)
我需要将 XML 转换为 Java 对象。我为此选择了 Declarative Stream Mapping (DSM),但不清楚如何将具有属性的嵌套元素映射到列表中。具体如何在下一篇的YAML文件中描述:
<categories>
<category id="1" parentId="2">Lorum Ipsum</category>
</categories>
我尝试了所有的选项,但都没有成功。
以下是我运行.
的代码片段
DSM(yaml):
result:
type: object
path: /catalog/shop
fields:
name:
path: name
company:
path: company
url:
path: url
platform:
path: platform
agency:
path: agency
email:
path: email
currencies:
type: array
path: currencies/currency
fields:
id:
xml:
attribute: true
rate:
xml:
attribute: true
categories:
type: array
path: categories/category
fields:
id:
xml:
attribute: true
parentId:
xml:
attribute: true
deliveryOptions:
type: array
path: delivery-options/option
fields:
cost:
xml:
attribute: true
days:
xml:
attribute: true
offers:
type: array
path: offers/offer
fields:
id:
xml:
attribute: true
available:
xml:
attribute: true
type:
xml:
attribute: true
param:
path: param
offer:
fields:
url:
path: url
price:
path: price
# shortened due to length
XML 要转换的文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<catalog date="2019-09-08 22:37">
<shop>
<name>company name</name>
<company>Microsoft</company>
<url>https://microsoft.com</url>
<platform>woefjwoefi</platform>
<agency>Agent</agency>
<email>billi@ms.com</email>
<currencies>
<currency id="USD" rate="1"/>
</currencies>
<categories>
<category id="398" parentId="198">Lorum Ipsum</category>
<category id="409">Uncategorized</category>
</categories>
<offers>
<offer id="2016" available="true" type="vendor.model">
<url>https://ms.com/id/1</url>
<price>35.00</price>
<currencyId>USD</currencyId>
<categoryId>168</categoryId>
<picture>https://ms.com/image/cache/catalog/8987-600x600.jpg</picture>
<store>true</store>
<pickup>true</pickup>
<delivery>true</delivery>
<vendor>MS</vendor>
<vendorCode>MS-10111</vendorCode>
<model>plasdf</model>
<downloadable>false</downloadable>
<param name="Weight">0.0</param>
</offer>
<offer id="2017" available="true" type="vendor.model">
<url>https://ms.com/id/2</url>
<price>250.00</price>
<currencyId>USD</currencyId>
<categoryId>201</categoryId>
<picture>https://ms.com/image/cache/catalog/aktiv-600x600.png</picture>
<store>true</store>
<pickup>true</pickup>
<delivery>true</delivery>
<vendor>MS</vendor>
<vendorCode>MS03238</vendorCode>
<model>woeifjwoef wefw fw we</model>
<description>wiefwof wef</description>
<downloadable>false</downloadable>
<weight>30.0</weight>
<param name="Weight">30.0</param>
</offer>
</offers>
</shop>
</catalog>
Java:
public class Shop {
private String name;
private String company;
private String url;
private String platform;
private String agency;
private String email;
private List<Currencies> currencies;
private List<Categories> categories;
private List<DeliveryOptions> deliveryOptions;
private List<Offers> offers;
// getters/setters
}
class Currencies {
// getters/setters
}
class Categories {
// getters/setters
}
class DeliveryOptions {
// getters/setters
}
class Offers {
// getters/setters
}
输出:
{
"name" : "company name",
"company" : "Microsoft",
"url" : "https://microsoft.com",
"platform" : "woefjwoefi",
"agency" : "Agent",
"email" : "billi@ms.com",
"currencies" : null,
"categories": null,
"deliveryOptions": null,
"offers": null
}
我做了一些轻微的缩进调整,你的 dsm 配置文件工作得很好。
DSM.yml
result:
type: object
path: /catalog/shop
fields:
name:
path: name
company:
path: company
url:
path: url
platform:
path: platform
agency:
path: agency
email:
path: email
currencies:
type: array
path: currencies/currency
fields:
id:
xml:
attribute: true
rate:
xml:
attribute: true
categories:
type: array
path: categories
xml:
path: categories/category
fields:
name:
path: ./
id:
xml:
attribute: true
parentId:
xml:
attribute: true
deliveryOptions:
type: array
path: delivery-options/option
fields:
cost:
xml:
attribute: true
days:
xml:
attribute: true
offers:
type: array
path: offers/offer
fields:
id:
xml:
attribute: true
available:
xml:
attribute: true
type:
xml:
attribute: true
param:
path: param
url: default
price: default
currencyId: default
categoryId: default
输出:
{
"name" : "company name",
"company" : "Microsoft",
"url" : "https://microsoft.com",
"platform" : "woefjwoefi",
"agency" : "Agent",
"email" : "billi@ms.com",
"currencies" : [ {
"id" : "USD",
"rate" : 1
} ],
"categories" : [ {
"id" : 398,
"parentId" : 198,
"name" : "Lorum Ipsum"
}, {
"id" : 409,
"parentId" : null,
"name" : "Uncategorized"
} ],
"deliveryOptions" : null,
"offers" : [ {
"id" : "2016",
"available" : true,
"type" : "vendor.model",
"url" : "https://ms.com/id/1",
"price" : 35.0,
"currencyId" : "USD",
"categoryId" : "168",
}, {
"id" : "2017",
"available" : true,
"type" : "vendor.model",
"url" : "https://ms.com/id/2",
"price" : 250.0,
"currencyId" : "USD",
"categoryId" : "201",
} ]
}
这是我用来测试它的代码:
@Test
public void dsmParsing() throws IOException {
InputStream is = new FileInputStream("src/main/resources/dsm.yml");
DSMBuilder builder = new DSMBuilder(is);
DSM dsm = builder.setType(DSMBuilder.TYPE.XML).create(Shop.class);
Shop shop = (Shop) dsm.toObject(new File("src/main/resources/shop.xml"));
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
System.out.println(ow.writeValueAsString(shop));
}
要回答有关带有属性的嵌套元素的问题,您必须考虑到当您有此定义时:
categories:
type: array
path: categories/category
当您定义 fields
时,您将描述元素 <category>
。
在下面的示例中,属性 id
和 parentId
将在 fields
段中定义为属性,但要获取实际 category
元素的值,您需要使用 ./
引用当前路径。如果您有子元素,则只需在 fields
段中添加这些子元素。
xml
<categories>
<category id="398" parentId="198">Lorum Ipsum</category>
</categories>
dsm
categories:
type: array
path: categories/category
fields:
name: ## you could call it 'value' or whatever you want
path: ./
id:
xml:
attribute: true
parentId:
xml:
attribute: true
下一个例子很有趣:
xml
<offers attr1="abc" attr2="def">
<offer id="2016" available="true">
<url>https://ms.com/id/1</url>
</offer>
</offers>
首先,您需要另一个 pojo 来正确表示 offers
及其属性:
店铺
public class Shop {
...
OffersList offers; // this attribute's name needs to match the one used in the dsm descriptor
}
新建class优惠列表
public class OffersList {
String attr1;
String attr2;
List<Offers> offer; // this attribute's name needs to match the one used in the dsm descriptor
}
最终的 dsm 将如下所示:
offers: ## name should match with Shop's attribute 'offers' (OffersList)
type: object ## now offers is an object, is mandatory to define 'fields'
path: offers ## focus is on the <offers> element
fields:
attr1:
xml:
attribute: true
attr2:
xml:
attribute: true
offer: ## name should match with OffersList's attribute 'offer'
type: array
path: ../offers/offer ## will go back a level to indicate <offers> <offer> should be parsed as an array
fields:
id:
xml:
attribute: true
available:
xml:
attribute: true
url:
path: url
输出
"offers" : {
"attr1" : "abc",
"attr2" : "def",
"offer" : [ {
"id" : "2016",
"available" : true,
"url" : "https://ms.com/id/1",
} ]
}
我需要将 XML 转换为 Java 对象。我为此选择了 Declarative Stream Mapping (DSM),但不清楚如何将具有属性的嵌套元素映射到列表中。具体如何在下一篇的YAML文件中描述:
<categories>
<category id="1" parentId="2">Lorum Ipsum</category>
</categories>
我尝试了所有的选项,但都没有成功。
以下是我运行.
的代码片段DSM(yaml):
result:
type: object
path: /catalog/shop
fields:
name:
path: name
company:
path: company
url:
path: url
platform:
path: platform
agency:
path: agency
email:
path: email
currencies:
type: array
path: currencies/currency
fields:
id:
xml:
attribute: true
rate:
xml:
attribute: true
categories:
type: array
path: categories/category
fields:
id:
xml:
attribute: true
parentId:
xml:
attribute: true
deliveryOptions:
type: array
path: delivery-options/option
fields:
cost:
xml:
attribute: true
days:
xml:
attribute: true
offers:
type: array
path: offers/offer
fields:
id:
xml:
attribute: true
available:
xml:
attribute: true
type:
xml:
attribute: true
param:
path: param
offer:
fields:
url:
path: url
price:
path: price
# shortened due to length
XML 要转换的文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<catalog date="2019-09-08 22:37">
<shop>
<name>company name</name>
<company>Microsoft</company>
<url>https://microsoft.com</url>
<platform>woefjwoefi</platform>
<agency>Agent</agency>
<email>billi@ms.com</email>
<currencies>
<currency id="USD" rate="1"/>
</currencies>
<categories>
<category id="398" parentId="198">Lorum Ipsum</category>
<category id="409">Uncategorized</category>
</categories>
<offers>
<offer id="2016" available="true" type="vendor.model">
<url>https://ms.com/id/1</url>
<price>35.00</price>
<currencyId>USD</currencyId>
<categoryId>168</categoryId>
<picture>https://ms.com/image/cache/catalog/8987-600x600.jpg</picture>
<store>true</store>
<pickup>true</pickup>
<delivery>true</delivery>
<vendor>MS</vendor>
<vendorCode>MS-10111</vendorCode>
<model>plasdf</model>
<downloadable>false</downloadable>
<param name="Weight">0.0</param>
</offer>
<offer id="2017" available="true" type="vendor.model">
<url>https://ms.com/id/2</url>
<price>250.00</price>
<currencyId>USD</currencyId>
<categoryId>201</categoryId>
<picture>https://ms.com/image/cache/catalog/aktiv-600x600.png</picture>
<store>true</store>
<pickup>true</pickup>
<delivery>true</delivery>
<vendor>MS</vendor>
<vendorCode>MS03238</vendorCode>
<model>woeifjwoef wefw fw we</model>
<description>wiefwof wef</description>
<downloadable>false</downloadable>
<weight>30.0</weight>
<param name="Weight">30.0</param>
</offer>
</offers>
</shop>
</catalog>
Java:
public class Shop {
private String name;
private String company;
private String url;
private String platform;
private String agency;
private String email;
private List<Currencies> currencies;
private List<Categories> categories;
private List<DeliveryOptions> deliveryOptions;
private List<Offers> offers;
// getters/setters
}
class Currencies {
// getters/setters
}
class Categories {
// getters/setters
}
class DeliveryOptions {
// getters/setters
}
class Offers {
// getters/setters
}
输出:
{
"name" : "company name",
"company" : "Microsoft",
"url" : "https://microsoft.com",
"platform" : "woefjwoefi",
"agency" : "Agent",
"email" : "billi@ms.com",
"currencies" : null,
"categories": null,
"deliveryOptions": null,
"offers": null
}
我做了一些轻微的缩进调整,你的 dsm 配置文件工作得很好。
DSM.yml
result:
type: object
path: /catalog/shop
fields:
name:
path: name
company:
path: company
url:
path: url
platform:
path: platform
agency:
path: agency
email:
path: email
currencies:
type: array
path: currencies/currency
fields:
id:
xml:
attribute: true
rate:
xml:
attribute: true
categories:
type: array
path: categories
xml:
path: categories/category
fields:
name:
path: ./
id:
xml:
attribute: true
parentId:
xml:
attribute: true
deliveryOptions:
type: array
path: delivery-options/option
fields:
cost:
xml:
attribute: true
days:
xml:
attribute: true
offers:
type: array
path: offers/offer
fields:
id:
xml:
attribute: true
available:
xml:
attribute: true
type:
xml:
attribute: true
param:
path: param
url: default
price: default
currencyId: default
categoryId: default
输出:
{
"name" : "company name",
"company" : "Microsoft",
"url" : "https://microsoft.com",
"platform" : "woefjwoefi",
"agency" : "Agent",
"email" : "billi@ms.com",
"currencies" : [ {
"id" : "USD",
"rate" : 1
} ],
"categories" : [ {
"id" : 398,
"parentId" : 198,
"name" : "Lorum Ipsum"
}, {
"id" : 409,
"parentId" : null,
"name" : "Uncategorized"
} ],
"deliveryOptions" : null,
"offers" : [ {
"id" : "2016",
"available" : true,
"type" : "vendor.model",
"url" : "https://ms.com/id/1",
"price" : 35.0,
"currencyId" : "USD",
"categoryId" : "168",
}, {
"id" : "2017",
"available" : true,
"type" : "vendor.model",
"url" : "https://ms.com/id/2",
"price" : 250.0,
"currencyId" : "USD",
"categoryId" : "201",
} ]
}
这是我用来测试它的代码:
@Test
public void dsmParsing() throws IOException {
InputStream is = new FileInputStream("src/main/resources/dsm.yml");
DSMBuilder builder = new DSMBuilder(is);
DSM dsm = builder.setType(DSMBuilder.TYPE.XML).create(Shop.class);
Shop shop = (Shop) dsm.toObject(new File("src/main/resources/shop.xml"));
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
System.out.println(ow.writeValueAsString(shop));
}
要回答有关带有属性的嵌套元素的问题,您必须考虑到当您有此定义时:
categories:
type: array
path: categories/category
当您定义 fields
时,您将描述元素 <category>
。
在下面的示例中,属性 id
和 parentId
将在 fields
段中定义为属性,但要获取实际 category
元素的值,您需要使用 ./
引用当前路径。如果您有子元素,则只需在 fields
段中添加这些子元素。
xml
<categories>
<category id="398" parentId="198">Lorum Ipsum</category>
</categories>
dsm
categories:
type: array
path: categories/category
fields:
name: ## you could call it 'value' or whatever you want
path: ./
id:
xml:
attribute: true
parentId:
xml:
attribute: true
下一个例子很有趣:
xml
<offers attr1="abc" attr2="def">
<offer id="2016" available="true">
<url>https://ms.com/id/1</url>
</offer>
</offers>
首先,您需要另一个 pojo 来正确表示 offers
及其属性:
店铺
public class Shop {
...
OffersList offers; // this attribute's name needs to match the one used in the dsm descriptor
}
新建class优惠列表
public class OffersList {
String attr1;
String attr2;
List<Offers> offer; // this attribute's name needs to match the one used in the dsm descriptor
}
最终的 dsm 将如下所示:
offers: ## name should match with Shop's attribute 'offers' (OffersList)
type: object ## now offers is an object, is mandatory to define 'fields'
path: offers ## focus is on the <offers> element
fields:
attr1:
xml:
attribute: true
attr2:
xml:
attribute: true
offer: ## name should match with OffersList's attribute 'offer'
type: array
path: ../offers/offer ## will go back a level to indicate <offers> <offer> should be parsed as an array
fields:
id:
xml:
attribute: true
available:
xml:
attribute: true
url:
path: url
输出
"offers" : {
"attr1" : "abc",
"attr2" : "def",
"offer" : [ {
"id" : "2016",
"available" : true,
"url" : "https://ms.com/id/1",
} ]
}