1

I've got some third party XML to parse in the following form. The number of tests is unbounded, but always an integer.

<tests>
    <test_1>
        <foo bar="baz" />
    </test_1>

    <test_2>
        <foo bar="baz" />
    </test_2>

    <test_3>
        <foo bar="baz" />
    </test_3>
</tests>

I'm currently parsing this with XPath, but it's a lot of messing around. Is there any way of expressing this style of XML in a XSD schema and generating JAXB classes from it.

As far as I can see this is impossible, the only thing possible is the <xs:any processContents="lax"/> technique from how can I define an xsd file that allows unknown (wildcard) elements? , however this allows any content, not specifically <test_<integer>. I just want to confirm I'm not missing some XSD/JAXB trick?

Note I would have preferred the XML to be structured like this. I may try to convince the third-party to change.

<tests>
    <test id="1">
        <foo bar="baz" />
    </test>

    <test id="2">
        <foo bar="baz" />
    </test>

    <test id="3">
        <foo bar="baz" />
    </test>
</tests>
Community
  • 1
  • 1
Adam
  • 35,919
  • 9
  • 100
  • 137
  • XSD's are centered around a fixed set of elements/types. JAXB simply creates classes from them. How could the number of different elements with the naming scheme "test_xxx" be determined? --- I see an alternative, however: First use an XSLT to change the incoming XML with those elements to one that fits your needs and uses the `` naming scheme. For that you can easily write an XSD and generate JAXB classes from it. – Seelenvirtuose Sep 04 '16 at 10:50

2 Answers2

1

While there are ways of dealing with elements with structured names such as numeric suffixes,

you really should fix the underlying XML design (test_1 should be test) instead.

Community
  • 1
  • 1
kjhughes
  • 106,133
  • 27
  • 181
  • 240
0

For completeness here is full working example of using XSLT to transform the <test_N> input into <test id="N"> style

<tests>
    <test_1>
        <foo bar="baz" />
    </test_1>
    <test_2>
        <foo bar="baz" />
    </test_2>
    <test_1234>
        <foo bar="baz" />
    </test_1234>
    <other>
        <foo></foo>
    </other>
</tests>

XSL

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[substring(name(), 1, 5) = 'test_']">
        <xsl:element name="test">
            <xsl:attribute name="id"><xsl:value-of select="substring(name(), 6, string-length(name()) - 5)" /></xsl:attribute>
            <xsl:copy-of select="node()" />
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

Code

File input = new File("test.xml");
File stylesheet = new File("test.xsl");

StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
StringWriter writer = new StringWriter();
transformer.transform(new StreamSource(input), new StreamResult(writer));

System.out.println(writer);

Output

<?xml version="1.0" encoding="UTF-8"?>
<tests>
    <test id="1">
        <foo bar="baz"/>
    </test>

    <test id="2">
        <foo bar="baz"/>
    </test>

    <test id="1234">
        <foo bar="baz"/>
    </test>

    <other>
        <foo/>
    </other>
</tests>
Adam
  • 35,919
  • 9
  • 100
  • 137