SimpleXML:对多种类型使用id属性

时间:2014-06-23 11:37:38

标签: java xml simple-framework

我使用SimpleXML将XML解析为Java对象,但我无法解析此文件:

<pets>
    <cats>
        <cat id="0" talk="miaou" />
        <cat id="1" talk="MIWAOUHAUOHou" />
    </cats>
    <dogs>
        <dog id="0"/>
    </dogs>
    <mine>
        <cat ref="1"/>
    </mine>
</pets>

使用此Java类:

@Default
@Root(name = "pets")
public class SimpleIds
{
    @ElementList(required = false)
    public ArrayList<Cat> cats;

    @ElementList(required = false)
    public ArrayList<Dog> dogs;

    @Root(name = "cat")
    public static class Cat
    {
        @Attribute
        public String talk;

        public void talk()
        {
            System.out.println(talk);
        }
    }

    @Root(name = "dog")
    public static class Dog
    {

    }

    @Element
    public Mine mine;

    @Root(name = "mine")
    public static class Mine
    {
        @Element
        public Cat cat;
    }
}

这个Serializer:

Strategy strategy = new CycleStrategy("id", "ref");
Serializer serializer = new Persister(strategy);
SimpleIds xml = serializer.read(SimpleIds.class, new File("simpleIds.xml"));
xml.mine.cat.talk();

它让我不高兴:

org.simpleframework.xml.strategy.CycleException: Element '0' already exists

使用SimpleXML这种xml文件是不可能的?或者它只是一个糟糕的xml格式?

修改:如果我将cat id="0"更改为cat id="2",那就像魅力一样......

3 个答案:

答案 0 :(得分:1)

在CycleStrategy的构造函数中,您可以传入参数以指定是否使用“id”作为identitfy元素或其他内容的属性。这里引起异常是因为它注意到两个具有相同“id”的元素。试试这个

CycleStrategy s = new CyctleStragegy("myid", "myreference")

它会起作用。

答案 1 :(得分:0)

您的XML非常完美。我不知道Simple Framework但我已经完成了JAXB。

如果它有帮助,我已经使用过JAXB。

这是完美的例子。

@XmlRootElement(name ="cat")
@XmlAccessorType(XmlAccessType.FIELD)
public class Cat {

    private String catName;
    private int id;

        Getters And Setters
}

@XmlRootElement(name ="dog")
@XmlAccessorType(XmlAccessType.FIELD)
public class Dog {

    private String dogName;
        private int id;
        Getters And Setters
}

@XmlRootElement(name = "cats")
@XmlAccessorType(XmlAccessType.FIELD)
public class Cats {

    @XmlElement(name = "cat")
    private List<Cat> cats;
        Getters And Setters
}


@XmlRootElement(name = "dogs")
@XmlAccessorType(XmlAccessType.FIELD)
public class Dogs {

    @XmlElement(name = "dog")
    private List<Dog> dogs;
        Getters And Setters
}

@XmlRootElement(name ="pets")
@XmlAccessorType(XmlAccessType.FIELD)
public class Pet {

    @XmlElement
    private Dogs dogs; 
    @XmlElement
    private Cats cats;
        Getters And Setters
}

我测试过它请测试一下。

答案 2 :(得分:0)

最后我在W3C Recommendation找到了答案:

  

文档中“ID”类型的所有属性的值(包括所有xml:id属性)唯一

这意味着我的输入XML 不正确

我无法改变它,因为我从软件中收到它但我必须在阅读之前格式化它(并反向写回来)以获得类似这样的内容:

<pets>
    <cats>
        <cat id="cat-0" talk="miaou" />
        <cat id="cat-1" talk="MIWAOUHAUOHou" />
    </cats>
    <dogs>
        <dog id="dog-0"/>
    </dogs>
    <mine>
        <cat ref="cat-1"/>
    </mine>
</pets>

编辑:以下代码可以在SimpleXML中为您自动完成这些操作:

/*
 * Copyright (C) 2014, Mathieu Lavigne <bludwarf@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing 
 * permissions and limitations under the License.
 */
package org.simpleframework.xml.strategy;

import static org.simpleframework.xml.strategy.Name.*;

import java.util.Map;

import org.simpleframework.xml.core.Persister;
import org.simpleframework.xml.stream.Node;
import org.simpleframework.xml.stream.NodeMap;

/**
 * CycleStrategy for SimpleXML allowing having duplicate IDs on nodes from different types.
 * 
 * <p>Known limitations : </p>
 * 
 * <ul>
 * <li>as for Legacy CycleStrategy, new ids are generated for <b>every node</b> when calling {@link Persister#write(Object, java.io.File)}
 * </ul>
 * 
 * @author bludwarf@gmail.com
 * @since 26 juin 2014
 */
public class TypedCycleStrategy extends CycleStrategy
{
    private String mark;
    private String refer;

    public TypedCycleStrategy()
    {
        this(MARK, REFER, LABEL, LENGTH);
    }

    public TypedCycleStrategy(String mark, String refer)
    {
        this(mark, refer, LABEL, LENGTH);
    }

    public TypedCycleStrategy(String mark, String refer, String label)
    {
        this(mark, refer, label, LENGTH);
    }


    public TypedCycleStrategy(String mark, String refer, String label, String length)
    {
        super(mark, refer, label, length);
        this.mark = mark;
        this.refer = refer;
    }

    public Value read(Type type, NodeMap node, Map map)
            throws Exception
    {
        // Unique id
        makeUniqueAttribute(mark, node, type);

        // Unique ref
        makeUniqueAttribute(refer, node, type);

        return super.read(type, node, map);
    }


    /**
     * @param attribute mark OR refer
     * @param node current node
     * @param type node type
     * @return the uniqueId created
     * @throws Exception
     */
    public static String makeUniqueAttribute(String attribute, NodeMap node, Type type) throws Exception
    {
        final Node entry = node.remove(attribute);
        String uniqueId = null;

        // Attribute found ?
        if (entry != null)
        {
            // Replace it to make it unique
            final String id = entry.getValue();
            uniqueId = type.getType().getName() + "-" + id;
            node.put(attribute, uniqueId);
        }

        return uniqueId;
    }

}

注意:不要更改包裹声明!

相应的Serializer:

Strategy strategy = new TypedCycleStrategy("id", "ref");
Serializer serializer = new Persister(strategy);
SimpleIds xml = serializer.read(SimpleIds.class, new File("simpleIds.xml"));
xml.mine.cat.talk();