使用xslt,根据第二个xml文档的内容转换一个xml文档

时间:2009-03-15 04:45:38

标签: xslt filtering

我有一组文档隐式定义第二组对象的允许字段,这些对象必须转换为第三组文档( 哪个“规则”文档使用取决于被转换文件的内容,例如

<!-- One example rules document --> 
<document object="obj1_rules">
<field name="A"/>
<field name="B"/>
<field name="C"/>
</document>

<!-- Document to be tranformed based upon obj1_rules--> 
<document object="obj1">
<field name="A"/>
<field name="B"/>
<field name="C"/>
<field name="D"/>
<field name="E"/>
</document>

<!-- Desired result--> 
<document object="obj1">
<newfield name="A"/>
<newfield name="B"/>
<newfield name="C"/>
</document>

是否可以使用xslt进行此转换?

我看到"There is no way in XSLT of constructing XPath expressions (e.g. variable references) at run-time."所以我运气不好,或者我只是错误地看待这个问题?谢谢!

3 个答案:

答案 0 :(得分:2)

这是一个简单的解决方案

此转化

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
<!--                                                   -->  
    <xsl:variable name="vrtfRules">
        <document object="obj1_rules">
            <field name="A"/>
            <field name="B"/>
            <field name="C"/>
        </document>
    </xsl:variable>
<!--                                                   -->  
    <xsl:variable name="vRules" select=
     "document('')/*/xsl:variable
                   [@name = 'vrtfRules']
                     /*
     "/>
<!--                                                   -->  
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
<!--                                                   -->  
    <xsl:template match="field">
      <xsl:if test="@name = $vRules/*/@name">
        <newfield>
          <xsl:apply-templates select="node()|@*"/>
        </newfield>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

应用于原始提供的源XML文档时:

<document object="obj1">
    <field name="A"/>
    <field name="B"/>
    <field name="C"/>
    <field name="D"/>
    <field name="E"/>
</document>

产生所需的结果:

<document object="obj1">
   <newfield name="A"/>
   <newfield name="B"/>
   <newfield name="C"/>
</document>

注意“规则文档”仅在样式表中用于紧凑性。如果它是一个单独的文档,则只需使用实际href调整所使用的document()函数。

答案 1 :(得分:1)

也许我过于简单了,但是你的“规则文档”不能简单地成为XSLT的原因是什么?

答案 2 :(得分:1)

好吧,我明白为什么你想在一个简单的xml文件中使用规则,而不是在一个完整的xsl样式表中,但你只是跳过一个步骤。

您需要制作一个xsl样式表,将xml规则文档转换为xsl样式表,然后将其应用到源xml上。

诀窍在于命名空间,不会因应用的xsl规则和生成的xsl规则而混淆。

    <?xml version="1.0" ?>
    <xsl:stylesheet
        xmlns="YOUR_NAMESPACE_HERE"
        xmlns:output="http://www.w3.org/1999/XSL/Transform"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">

        <xsl:output
            method="xml"
            indent="yes"
            media-type="text/xsl" />

        <xsl:template match="/">
            <output:stylesheet version="2.0">
                <xsl:apply-templates />
            </output:stylesheet>
        </xsl:template>

        <xsl:template match="document[@object]">
            <output:template match="document[@object='{@object}']">
                <output:copy>
                    <xsl:apply-templates />
                </output:copy>
            </output:template>
        </xsl:template>

        <xsl:template match="field[@name]">
            <output:if test="field[@name='{@name}']">
                <output:copy-of select="field[@name='{@name}']" />
            </output:if>
        </xsl:template>

    </xsl:stylesheet>

我假设您在规则和文档中使用相同的文档对象属性(这样更简单)。

因此,您可以通过上面的样式表运行规则文档。结果是一个新的xsl样式表,它完全按照您在xml规则文档中描述的那样执行。然后,将生成的样式表应用到源文档中,您应该得到预期的结果。