XSLT - 转换几个兄弟标签,但保持其余部分不变

时间:2015-07-29 15:52:29

标签: xslt xslt-2.0

我试图转换输入XML

<?xml version="1.0" encoding="utf-8"?>
<request>
    <customer_data>
        <contact_info>
            <name>john doe</name>
            <dob_year>1984</dob_year>
            <dob_month>09</dob_month>
            <dob_date>14</dob_date>
            <gender>m</gender>
        </contact_info>
    </customer_data>
</request>

所以它看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<request>
    <customer_data>
        <contact_info>
            <name>john doe</name>
            <dob>1984-09-14</dob>
            <gender>m</gender>
        </contact_info>
    </customer_data>
</request>

以下是 XSLT ,我正在使用:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="contact_info">
        <xsl:copy>
            <dob>
                <xsl:value-of select="(dob_year, dob_month, dob_date)" separator="-"/>
            </dob>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

这是我得到的结果

<?xml version="1.0" encoding="utf-8"?><request>
    <customer_data>
        <contact_info><dob>1984-09-14</dob></contact_info>
    </customer_data>
</request>

如何转换dob_ *标签,保持contact_info的其余部分完好无损?

更新

根据以下答案,我目前的解决方案是

<xsl:template match="contact_info">
    <xsl:copy>
        <xsl:apply-templates select="*[not(starts-with(name(), 'dob'))]"/>
        <dob>
            <xsl:value-of select="(dob_year, dob_month, dob_date)" separator="-"/>
        </dob>
    </xsl:copy>
</xsl:template>

这对我有用,但是没有更优雅的方式表达&#34; 将转换应用于给定元素,并将模板应用于其余&#34;?现在,我有点坚持使用这个表达式*[not(starts-with(name(), 'dob'))]并不是那么糟糕,但是如果&#34; DOB&#34;属性改变了,我也必须解决这个问题。

2 个答案:

答案 0 :(得分:1)

更改

<xsl:template match="contact_info">
    <xsl:copy>
        <dob>
            <xsl:value-of select="(dob_year, dob_month, dob_date)" separator="-"/>
        </dob>
    </xsl:copy>
</xsl:template>

<xsl:template match="contact_info">
    <xsl:copy>
        <xsl:apply-templates select="dob_year/preceding-sibling::node()"/>
        <dob>
            <xsl:value-of select="(dob_year, dob_month, dob_date)" separator="-"/>
        </dob>
        <xsl:apply-templates select="dob_date/following-sibling::node()"/>
    </xsl:copy>
</xsl:template>

答案 1 :(得分:1)

这是你可以看到它的一种方式:

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

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

<xsl:template match="dob_year">
    <dob>
        <xsl:value-of select="(., ../dob_month, ../dob_date)" separator="-"/>
    </dob>
</xsl:template>

<xsl:template match="dob_month|dob_date"/>

</xsl:stylesheet>

这是另一个:

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

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

<xsl:template match="contact_info">
    <xsl:copy>
        <xsl:copy-of select="name|gender"/>
        <dob>
            <xsl:value-of select="(dob_year, dob_month, dob_date)" separator="-"/>
        </dob>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

编辑:

为了仅枚举DOB元素并且只进行一次,您可以这样做:

<xsl:template match="contact_info">
    <xsl:variable name="dob-fields" select="(dob_year, dob_month, dob_date)" />
    <xsl:copy>
        <xsl:apply-templates select="* except $dob-fields"/>
        <dob>
            <xsl:value-of select="$dob-fields" separator="-"/>
        </dob>
    </xsl:copy>
</xsl:template>