使用XSLT对条件进行XML键/值操作

使用XSLT对条件进行XML键/值操作,xml,xslt,xml-parsing,xslt-1.0,xslt-2.0,Xml,Xslt,Xml Parsing,Xslt 1.0,Xslt 2.0,我有这样的数据- <item> <name>Bob</name> <fav_food>pizza</fav_food> <key>Salary</key> <value /> <value2>1000</value2> <value3 /> </item> <item> <nam

我有这样的数据-

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

上下快速移动
披萨
薪水
1000
我希望我的输出像这样-

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

上下快速移动
披萨
1000
在这种情况下,Salary的值为1000,因为值为空,而value2不是(值的优先级高于value2,后者的优先级高于value3)

可以保证value、value2和value3都存在,并且其中只有一个是非空的。是否可以使用XSLT转换来实现这一点

目前,这是我的转换

<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>

我想你可以简单地

<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>


您可能想要或需要调整元素名称的生成,但我没有应用您的
name=“{substring before(substring before)(,“{'),“}')”}
,因为我在您的输入示例中没有看到任何大括号。

我打算建议
xsl:value of select=“../(value,value2,value3)”分隔符=“
,但想法是一样的。但是考虑到“优先级”的说法,我强烈怀疑我们还没有看到一个完整的规范。每个
会有多个
吗?知道这一点很重要。根据你的密码,我猜不会。另外,您的代码是否正常工作,并且您只是想要一种更好的方法来完成它?或者你的代码有问题吗?如果是这样,请显示实际输出。我保证每个项目只有一个键。我的代码不起作用,基本上我得到的所有键都是空字符串,不管我的值是什么。空字符串在哪里?请显示您得到的输出。还有,为什么你有
子字符串-after()
等等。当你的输入中没有
{
时?或者如果你显示的输入不真实,请显示真实的输入。子字符串-after()是因为我的密钥格式像
{Salary}
而我必须取出{}。Mark发布的解决方案仍然有效(当我添加子字符串-after()时)。