简体   繁体   中英

Attempting to write a parser for my own XML style file format, getting FileNotFoundException, is there anything in particular I'm doing wrong?

So basically, I'm trying to write a 2d skeletal animation editor as well as a framework to make it easy use the same animations created in the editor in a game. The biggest problem is that I haven't written an XML parser before, so I have a feeling I may be doing something completely wrong, but I'm not sure what it is.

Here is an example file in my format:

<skeleton name="skeleton1">

    <bones>
        <bone name="bone1" id="1" textureLoc="/imgs/test.png">
            <position>x,y</position>
            <rotation>float</rotation>
            <scale>float</scale>
        </bone>

        <bone name="bone2" id="2" textureLoc="/imgs/text2.png">
            <position>x,y</position>
            <rotation>float</rotation>
            <scale>float</scale>
        </bone>
    </bones>

    <animation name="anim1">
        <keyframe frameToPlay="1">
            <bone id="1" transPosition="x,y" transRotation="float" transScale="float">
            </bone>

            <bone id="2" transPosition="x,y" transRotation="float" transScale="float">
            </bone>
        </keyframe>

        <keyframe frameToPlay="50">
            <bone id="1" transPosition="x,y" transRotation="float" transScale="float">
            </bone>

            <bone id="2" transPosition="x,y" transRotation="float" transScale="float">
            </bone>
        </keyframe>
    </animation>

    <animation name="anim2">
        <keyframe frameToPlay="1">
            <bone id="1" transPosition="x,y" transRotation="float" transScale="float">
            </bone>

            <bone id="2" transPosition="x,y" transRotation="float" transScale="float">
            </bone>
        </keyframe>

        <keyframe frameToPlay="50">
            <bone id="1" transPosition="x,y" transRotation="float" transScale="float">
            </bone>

            <bone id="2" transPosition="x,y" transRotation="float" transScale="float">
            </bone>
        </keyframe>
    </animation>
</skeleton>



Here is a description of the way I have organized this system, if it makes my code more understandable:

AnimationSystem – Management interface for all animations in game, handles updating of each skeleton
--List of skeletons
---Skeletons represent each object
--Update method that updates each skeleton with the game’s current frame
Animation
--List of keyframes
--List of frames, in ascending order, pulled from the list of keyframes
---Order index in list corresponds to order index in list of keyframes
---Should help to speed things up a little bit, no need to search every keyframe to determine which one has a frame value matching the one that is currently needed.
---Will be determined by a set up method after assets are loaded, but before the animation can be used.
--Method to return a keyframe that corresponds to a frame passed to the method
Skeleton
--List of animations
--List of bones
--Value to hold the currently selected animation
--Value to hold the current frame in the game
--Value to hold the name of the skeleton
--Upon moving to a new frame, searches currently selected animation’s list of frames to see if a keyframe should be “played” this frame. If a keyframe exists that should be played at this frame, it should go through each bone in its list of bones, and set the properties of each bone to the properties listed in the keyframe according to the bone’s id.
Bone
--Value to hold the stationary position
--Value to hold the stationary rotation
--Value to hold the stationary scale
--Value to hold the transformed position
--Value to hold the transformed rotation
--Value to hold the transformed scale
--Image value that holds the texture of the bone
--Value to hold the id of the bone within its skeleton
--Value to hold the name of the bone (Used in the editor)
--Method that takes 3 values (position, rotation and scale in that order) and set’s its own transformed pos, rot and scale values to those passed in.
Keyframe
--List of scale values
--List of position values
--List of rotation values
--List of bone ids
---Index of bone id in list matches up to index in scale, position and rotation lists so that the properties can be associated with the bone
--Time value at which the keyframe will be played
--Method to return the scale value of a bone as determined by the bone id passed in
--Method to return the position value of a bone as determined by the bone id passed in
--Method to return the rotation value of a bone as determined by the bone id passed in



The associated method that I've written to attempt to parse this code is as follows:

public static Skeleton parseSkeletonFile(String location) throws FileNotFoundException, IOException
    {
        try
        {
            Skeleton skelToReturn = null;

            File fileToLoad = new File(location);

            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(fileToLoad);

            doc.getDocumentElement().normalize();

            NodeList skelList = doc.getElementsByTagName("skeleton");

            for (int counter = 0; counter < skelList.getLength(); counter++)
            {
                Node skelNode = skelList.item(counter);

                Element skelElement = (Element)skelNode;

                skelToReturn = new Skeleton(skelElement.getAttribute("name"));

                NodeList allNodes = skelNode.getChildNodes();

                for (int counter2 = 0; counter2 < allNodes.getLength(); counter2++)
                {
                    Node currentNode = allNodes.item(counter2);

                    if (currentNode.getNodeName() == "bones")
                    {
                        NodeList bonesNL = currentNode.getChildNodes();

                        for (int counter3 = 0; counter3 < bonesNL.getLength(); counter3++)
                        {
                            Node currentBone = bonesNL.item(counter3);
                            Element currentBoneE = (Element)currentBone;

                            Bone bone = new Bone(
                                    currentBoneE.getAttribute("name"),
                                    new Point(
                                        Float.valueOf(currentBoneE.getElementsByTagName("position").item(0).getTextContent().split(",")[0]),
                                        Float.valueOf(currentBoneE.getElementsByTagName("position").item(0).getTextContent().split(",")[1])
                                        ),
                                    Float.valueOf(currentBoneE.getElementsByTagName("rotation").item(0).getTextContent()),
                                    Float.valueOf(currentBoneE.getElementsByTagName("scale").item(0).getTextContent()),
                                    Integer.valueOf(currentBoneE.getAttribute("id"))
                                    );



                            bone.setImage(new Image(currentBoneE.getAttribute("textureLoc")));

                            skelToReturn.bones.add(bone);
                        }
                    }

                    if (currentNode.getNodeName() == "animation")
                    {
                        NodeList animsNL = currentNode.getChildNodes();

                        for (int counter4 = 0; counter4 < animsNL.getLength(); counter4++)
                        {
                            Node currentAnim = animsNL.item(counter4);
                            Element currentAnimE = (Element)currentAnim;

                            Animation animation = new Animation(currentAnimE.getAttribute("name"));

                            NodeList keyframesNL = currentAnim.getChildNodes();

                            for (int counter5 = 0; counter5 < keyframesNL.getLength(); counter5++)
                            {
                                Node currentKeyframe = keyframesNL.item(counter5);
                                Element currentKeyframeE = (Element)currentKeyframe;

                                Keyframe keyframe = new Keyframe(Integer.valueOf(currentKeyframeE.getAttribute("frameToPlay")));

                                NodeList kfBonesNL = currentKeyframe.getChildNodes();

                                for (int counter6 = 0; counter6 < kfBonesNL.getLength(); counter6++)
                                {
                                    Node currentBoneTrans = kfBonesNL.item(counter6);
                                    Element currentBoneTransE = (Element)currentBoneTrans;

                                    keyframe.boneIDs.add(Integer.valueOf(currentBoneTransE.getAttribute("id")));
                                    keyframe.positions.add(new Point(Float.valueOf(currentBoneTransE.getAttribute("transPosition").split(",")[0]), Float.valueOf(currentBoneTransE.getAttribute("transPosition").split(",")[1])));
                                    keyframe.rotations.add(Float.valueOf(currentBoneTransE.getAttribute("transRotation")));
                                    keyframe.scales.add(Float.valueOf(currentBoneTransE.getAttribute("transScale")));
                                }
                                animation.keyframes.add(keyframe);
                                animation.frames.add(keyframe.getTimeToBePlayed());
                            }

                            skelToReturn.animations.add(animation);
                            skelToReturn.animationNames.add(animation.name);
                        }
                    }
                }
            }
            if (skelToReturn != null)
                return skelToReturn;
            else
                return null;
        } catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }



Here a snippet of the code I'm using to test the parser as is:

AnimationSystem animator = new AnimationSystem();
        try {
            skeleton = animator.parseSkeletonFile(getClass().getResource("SkeletonTest.xml").getPath());
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (skeleton != null)
        {
            System.out.println(skeleton.name);
        }


This is in the init method of a simple game built in Slick2D. The file I'm trying to load, SkeletonTest.xml, is in the same package as the class that is calling the parsing method. It's contents are simply:

<skeleton name="TestSkeleton">

</skeleton>



And this is the error message I am receiving in its entirety:

java.io.FileNotFoundException: D:\Eclipse%20Workspace\2dSkeletalAnimator\bin\org\jason\animatorTests\SkeletonTest.xml (The system cannot find the path specified)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(Unknown Source)
    at java.io.FileInputStream.<init>(Unknown Source)
    at sun.net.www.protocol.file.FileURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
    at org.jason.skeletalanimator.AnimationSystem.parseSkeletonFile(AnimationSystem.java:42)
    at org.jason.animatorTests.AnimatorTest1.init(AnimatorTest1.java:32)
    at org.newdawn.slick.AppGameContainer.setup(AppGameContainer.java:433)
    at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:357)
    at org.jason.animatorTests.AnimatorTest1.main(AnimatorTest1.java:65)



Sorry for the somewhat general question and the amount of background information required, but I've tried just about everything to get this to work short of rewriting the body of the parsing method. I'd rather not go through that mess again. So I'm hoping someone with more experience loading data from XML style files can help me out here. I thank whoever that is in advance for giving me some of their time.

One problem is that you are trying to get a File from a classpath entry. The getPath() method returns a file URL, not a file path. You are then attempting to load that as if it were a filepath, which causes the problem.

It would be a lot easier, if you were to use getClass().getResourceAsStream() which gives you an InputStream .

Instead of passing a location , you could pass an InputStream to your parseSkeleton method and change to using DocumentBuilder#parse(InputStream) .

The additional advantage to using an InputStream is that if you package up your classes in a JAR file, you can still load your resource (you wouldn't be able to get a valid File path to inside your JAR). Or your skeleton definition could come from any other InputStream , eg network etc.

java.io.FileNotFoundException: D:\\Eclipse%20Workspace\\2dSkeletalAnimator\\bin\\org\\jason\\animatorTests\\SkeletonTest.xml (The system cannot find the path specified)

There's a space in your path. This is the problem. Notice the %20. I can't see where it is being encoded, but you should decode the file path before you make the call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM