XML Key/value manipulation on condition using XSLT

2019-07-31 01:34发布

问题:

I have data like this -

<item>
    <name>Bob</name>
    <fav_food>pizza</fav_food>
    <key>Salary</key>
    <value />
    <value2>1000</value2>
    <value3 />
</item>

I want my output to look like this -

<item>
    <name>Bob</name>
    <fav_food>pizza</fav_food>
    <Salary>1000</Salary>
</item>

In this case, Salary gets the value of 1000 because value is empty and value2 is not (value has higher priority than value2, which has higher priority than value3).

It is guaranteed that value,value2 and value3 all exist, and only one of those is nonempty. Is it possible to use a XSLT transform to do this?

Currently, this is my transform.

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />  

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

<xsl:template match="key">
    <xsl:element name="{substring-before(substring-after(.,'{'),'}')}"> 
        <xsl:choose>
            <xsl:when test="value != ''">
                <xsl:value-of select="following-sibling::value" />
            </xsl:when>
            <xsl:when test="value2 != ''">
                <xsl:value-of select="following-sibling::value2" />
            </xsl:when>
            <xsl:when test="value3 != ''">
                <xsl:value-of select="following-sibling::value3" />
            </xsl:when>
        </xsl:choose>
   </xsl:element> 
</xsl:template>
</xsl:stylesheet>

回答1:

I think you can simply do

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />  

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

<xsl:template match="key">
  <xsl:element name="{.}">
    <xsl:copy-of select="../(value, value2, value3)/text()"/>
  </xsl:element>
</xsl:template>

<xsl:template match="item/value | item/value2 | item/value3"/>

</xsl:stylesheet>

You might want or need to adjust the element name generation but I have not applied your name="{substring-before(substring-after(.,'{'),'}')}" as I don't see any braces in your input sample.