A simpler, shorter and more generic (no element names hardcoded) solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*[not(*[2])]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
when this transformation is applied on the first provided XML document (corrected to be made well-formed):
<root>
<branch>
<foo>bar</foo>
</branch>
</root>
the wanted, correct result is produced:
<branch></branch>
When the same transformation is applied on the second provided XML document (again needed to be corrected for well-formedness):
<root>
<branch>
<foo>bar</foo>
</branch>
<branch>
<foo>baz</foo>
</branch>
</root>
again the wanted, correct output is produced:
<root>
<branch></branch>
<branch></branch>
</root>
Explanation:
The identity rule copies every node "as-is".
There are two templates that override the identity template for specific nodes and process these nodes in different ways.
The first overriding template matches a top element that doesn't have a second element child. It doesn't copy the element itself, but processes its children.
The second overriding template matches any element that is a grand-child of the top element. This template doesn't have a body, which means that all such matched element are ignored and not included in the output (in other words -- "deleted")
Do note:
This transformation can be applied to any XML document, regardless of the element names in it, and still produces the wanted, correct result.
For example, when applied on this XML document:
<t>
<b>
<f>brrr</f>
</b>
<b>
<f>bzzz</f>
</b>
</t>
the wanted, correct result is produced:
<t>
<b></b>
<b></b>
</t>
Contrast this to the result produced by the currently - accepted answer:
<t>
<b>
<f>brrr</f>
</b>
<b>
<f>bzzz</f>
</b>
</t>