Я думаю, что ваш XSLT может быть слишком сложным. Например, вам не обязательно нужен xsl: key .
То, что вы можете сделать, - это когда вы сопоставляете элемент Member , добавляете специальное кодирование для элемента FirstName , чтобы скопировать его, а затем просто продолжаете сопоставлять все дочерние элементы
<xsl:template match="Member">
<xsl:copy>
<xsl:copy-of select="FirstName"/>
<ExtraInfo>
<xsl:apply-templates />
</ExtraInfo>
</xsl:copy>
</xsl:template>
Однако вам потребуется пустой шаблон, чтобы снова соответствовать элементу FirstName, чтобы он не выводился дважды
<xsl:template match="FirstName" />
Вам также потребуются соответствующие шаблоны для ваших Книжных и Стационарных элементов, чтобы выполнить специальную обработку этих
<xsl:template match="Books|Stationery">
<Category>
<Name>
<xsl:value-of select="local-name()"/>
</Name>
<xsl:apply-templates select="*" mode="Attributes"/>
</Category>
</xsl:template>
Вам также потребуется шаблон для обработки дочерних элементов Book и Стационарные элементов. Я не уверен на 100%, что вы хотели с этим сделать, но в вашем ожидаемом результате выглядело, как будто вы хотели преобразовать их в attribute elements.
Вот XSLT полностью
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ex="http://exslt.org/dates-and-times" extension-element-prefixes="ex">
<xsl:strip-space elements="FirstName Surname Add1 Add2 City Email"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BatchMember">
<Batch>
<Version>1.0</Version>
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</Batch>
</xsl:template>
<xsl:template match="Member">
<xsl:copy>
<xsl:copy-of select="FirstName"/>
<ExtraInfo>
<xsl:apply-templates />
</ExtraInfo>
</xsl:copy>
</xsl:template>
<xsl:template match="FirstName" />
<xsl:template match="Books|Stationery">
<Category>
<Name>
<xsl:value-of select="local-name()"/>
</Name>
<xsl:apply-templates select="*" mode="Attributes"/>
</Category>
</xsl:template>
<xsl:template match="*" mode="Attributes">
<attribute>
<Name>
<xsl:value-of select="local-name()"/>
</Name>
<Value>
<xsl:choose>
<xsl:when test=". = 1">True</xsl:when>
<xsl:otherwise>False</xsl:otherwise>
</xsl:choose>
</Value>
</attribute>
</xsl:template>
</xsl:stylesheet>
При применении к вашему образцу входного XML выводится следующее:
<Batch>
<Version>1.0</Version>
<BatchMember>
<Member>
<FirstName>MICHAEL </FirstName>
<ExtraInfo>
<Category>
<Name>Books</Name>
<attribute>
<Name>Fiction</Name>
<Value>True</Value>
</attribute>
<attribute>
<Name>ChildrensBooks</Name>
<Value>False</Value>
</attribute>
</Category>
<Category>
<Name>Stationery</Name>
<attribute>
<Name>Art</Name>
<Value>False</Value>
</attribute>
<attribute>
<Name>Writing</Name>
<Value>False</Value>
</attribute>
</Category>
<CardsGifts>1</CardsGifts>
<ROINI>1</ROINI>
<Signed>1</Signed>
<Date>2011-10-04</Date>
</ExtraInfo>
</Member>
<Member>
<FirstName>JOHN </FirstName>
<ExtraInfo>
<Category>
<Name>Books</Name>
<attribute>
<Name>Fiction</Name>
<Value>True</Value>
</attribute>
<attribute>
<Name>ChildrensBooks</Name>
<Value>False</Value>
</attribute>
</Category>
<Category>
<Name>Stationery</Name>
<attribute>
<Name>Art</Name>
<Value>True</Value>
</attribute>
<attribute>
<Name>Writing</Name>
<Value>False</Value>
</attribute>
</Category>
<CardsGifts>1</CardsGifts>
<ROINI/>
<Signed>1</Signed>
<Date>2011-10-04</Date>
</ExtraInfo>
</Member>
</BatchMember>
</Batch>
Хотя он не совсем соответствует ожидаемому результату (например, он по-прежнему выводит CardsGifts элементов), я надеюсь, что он может дать вам над чем поработать.