Como transformar o XML com o XSLT?
<entities>
<entity>
<field>13</field>
</entity>
<entity>
<field>1</field>
</entity>
<entity>
<field>5</field>
</entity>
</entities>
e eu preciso transformá - lo nessa estrutura usando XSLT:
<entities>
<entity field="13"/>
<entity field="1"/>
<entity field="5"/>
</entities>
Este é o meu XSLT por agora.
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="field/text()">
<xsl:value-of select="concat('"', ., '"')"/>
</xsl:template>
Estou preso a transformar <field>
em atributo da entidade. Como fazer isso?
4 answers
Eu iria igualar ao nível da entidade em vez do nível do campo e faria algo do género:
<xsl:template match="entity">
<entity>
<xsl:attribute name="field"><xsl:value-of select="field/text()" /></xsl:attribute>
</entity>
</xsl:template>
Editar: o acima assume também um modelo de correspondência genérico, como na pergunta original. Para maior clareza, aqui está o arquivo XSL completo que eu testei contra a entrada da amostra. Como observado nos comentários, você pode querer combinar apenas com os nós de entidade no nó de entidades, embora para a amostra simples fornecida, não importa.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="entity">
<entity>
<xsl:attribute name="field"><xsl:value-of select="field/text()" /></xsl:attribute>
</entity>
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Isto produz a produção (testada em Eclipse no Mac):
<?xml version="1.0" encoding="UTF-8"?>
<entities>
<entity field="13"/>
<entity field="1"/>
<entity field="5"/>
</entities>
Tenta isto:
<xsl:for-each select="entities/entity">
<xsl:element name="entity">
<xsl:attribute name="field">
<xsl:value-of select="field"/>
</xsl:attribute>
</xsl:element>
</xsl:for-each>
Este código passará por todos os elementos entity
e criará um elemento com o atributo field
para cada um
Uma versão um pouco descritiva: Ambos podem também visar a entidade interna específica não apenas "campo", mas deixei-o genérico, uma vez que é tudo o que vemos na amostra.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="entities">
<entities>
<xsl:apply-templates/>
</entities>
</xsl:template>
<xsl:template match="entity">
<entity>
<xsl:for-each select="*">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</entity>
</xsl:template>
</xsl:stylesheet>
Saída
<entities xmlns="http://www.w3.org/1999/xhtml">
<entity field="13"></entity>
<entity field="1"></entity>
<entity field="5"></entity>
</entities>
Versão ligeiramente diferente com "transformar"
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="entities">
<entities>
<xsl:apply-templates/>
</entities>
</xsl:template>
<xsl:template match="entity">
<entity>
<xsl:for-each select="*">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</entity>
</xsl:template>
</xsl:transform>
Aponta apenas os elementos internos do campo:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="entities">
<entities>
<xsl:apply-templates/>
</entities>
</xsl:template>
<xsl:template match="entity">
<entity>
<xsl:for-each select="field">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:for-each>
</entity>
</xsl:template>
</xsl:transform>
Exemplo para copiar e apenas apontar para o campo, sem etiqueta de fecho na entidade, também omite a declaração xml.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="entities">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="entity">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="field">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:template>
</xsl:transform>
Resultado:
<entities>
<entity field="13"/>
<entity field="1"/>
<entity field="5"/>
</entities>
Mais Compacto versão do último:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="entities|entity">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="field">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:template>
</xsl:transform>
Note que isto é diferente da resposta anterior, é mais genérico, apenas fazendo qualquer aninhado <field></field>
num atributo no seu nó-mãe. Isto não se importa com os elementos entities
ou entity
especificamente e mais de perto corresponde à sua pergunta xsl.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()[not(self::field)]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="field">
<xsl:attribute name="{name()}">
<xsl:value-of select="text()"/>
</xsl:attribute>
</xsl:template>
</xsl:transform>