使用xslt重建xml:复制所有元素并在某些属性上应用函数

时间:2014-08-03 22:26:23

标签: xml xslt

以下是一条示例消息:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.w3.org/2005/Atom">
    <id>xxx</id>
    <atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
        <atom:id>atom_id_01</atom:id>
        <atom:content type="application/xml">
            <event xmlns="http://event" xmlns:sample="unknown_namespace" id="event_id_01" type="special_type">
                <sample:product a="a_01_before" b="b__01before" />
            </event>
        </atom:content>
    </atom:entry>
    <atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
        <atom:id>atom_id_02</atom:id>
        <atom:content type="application/xml">
            <event xmlns="http://event" xmlns:sample="unknown_namespace" id="event_id_02" type="special_type">
                <sample:product a="a_02_before" b="b_02_before" />
            </event>
        </atom:content>
    </atom:entry>
</root>
  1. 提取输入节点
  2. 在product / @ a和prodcut / @ b上应用函数(ConvertUtil.change(String value))。
  3. 结果应该是:

    <entries>
        <entry xmlns="http://www.w3.org/2005/Atom">
            <content>
                <event xmlns="http://event" id="event_id_01" type="special_type">
                    <product a="a_01_after" b="b_01_after"/>
                </event>
            </content>
        </entry>
        <entry xmlns="http://www.w3.org/2005/Atom">
            <content>
                <event xmlns="http://event" id="event_id_02" type="special_type">
                    <product a="a_02_after" b="b_02_after"/>
                </event>
            </content>
        </entry>
    </entries>
    

    我尝试过很多方法,发现命名空间太烦人了。我是否需要先删除命名空间?

    ---更新---

    我用两个xslt文件应用它。

    第一个将构建一个新格式的xml文件:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" method="xml" indent="no"/>
        <xsl:template match="/">
            <entries>
                <xsl:for-each select="//*[@type='special_type']">
                    <xsl:copy-of select="../.."/>
                </xsl:for-each>
            </entries>
        </xsl:template>
    </xsl:stylesheet>
    

    第二个将在某些属性上应用函数

    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:utils="com.example.util">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="//*/@a | //*/@b">
    
            <xsl:variable name="aTemp" select="..//@a"></xsl:variable>
            <xsl:variable name="bTemp" select="..//@b"></xsl:variable>
    
            <xsl:attribute name="a">
                <xsl:value-of select="utils:ConverterUtil.test($aTemp)"/>
            </xsl:attribute>
    
            <xsl:attribute name="b">
            <xsl:value-of select="utils:ConverterUtil.test($bTemp)"/>
            </xsl:attribute>
        </xsl:template>
    
    </xsl:stylesheet>
    

    然而,它有点奇怪的方式。我不喜欢它,因为像//*/@a这样的表达式非常依赖于a属性只出现一次的条件。还有更好的办法吗?

    例如,product/@a更好,因为它取决于整个xml结构。但我发现我需要在像sample:product/@a之类的元素之前明确指定命名空间。在我的情况下,问题是命名空间一直在变化。

2 个答案:

答案 0 :(得分:0)

以下是一个示例样式表,可帮助您入门:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:event="http://event"
    xmlns:sample="sample" exclude-result-prefixes="#all"
    version="2.0">

    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>

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

    <xsl:template match="atom:root">
        <entries>
            <xsl:apply-templates/>
        </entries>
    </xsl:template>

    <xsl:template match="atom:root/atom:id|atom:entry/atom:id"/>

    <xsl:template match="atom:entry">
        <xsl:element name="entry" namespace="http://www.w3.org/2005/Atom">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="atom:content">
        <xsl:element name="content" namespace="http://www.w3.org/2005/Atom">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="event:event">
        <xsl:element name="event" namespace="http://event">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*[local-name()='product']">
        <xsl:element name="product" namespace="http://event">
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <!-- Do your attribute templates here. Below is just a sample -->
    <xsl:template match="*[local-name()='product']/@a">
        <xsl:attribute name="a_test">changed_att</xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

尝试一下;比如:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:event="http://event">

<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="/atom:root">
    <entries>
        <xsl:apply-templates select="@*|node()"/>
    </entries>
</xsl:template>

<xsl:template match="event:event/*[local-name()='product']">
    <event:product>
        <xsl:attribute name="a">
            <xsl:value-of select="utils:ConverterUtil.test(@a)"/>
        </xsl:attribute>
        <xsl:attribute name="b">
            <xsl:value-of select="utils:ConverterUtil.test(@b)"/>
        </xsl:attribute>
    </event:product>
</xsl:template>

</xsl:stylesheet>