xslt合并两个xml文件,并在属性中预先指定选择值

时间:2015-12-15 08:39:48

标签: xml xslt

我有两个名为data1.xml和data2.xml的XML文件,使用XSLT我如何生成result.xml,在data2.xml中我使用selectValFrm属性来指定XPATH来选择值表单。和其他属性一样。

data1.xml作为

<inputRoot>
    <childOne>
        I am first child
    </childOne>
    <childTwo>
        <nestedChild id="1">
            I am second child
        </nestedChild>
    </childTwo> 
</inputRoot>

data2.xml

<result>
    <ChildOneDesc selectValFrm="root/childOne"></ChildOneDesc>
    <ChildTwoDesc>
        <value num="root/childTwo/nestedChild/@id" selectValFrm="root/childTwo/nestedChild"></value>
    </ChildTwoDesc> 
</result>

为result.xml

<result>
    <ChildOneDesc>
        I am first child
    </ChildOneDesc>
    <ChildTwoDesc>
        <value num="1">
            I am second child
        </value>
    </ChildTwoDesc> 
</result>

我写了一个XSLT,如:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:java="http://xml.apache.org/xslt/java" 
    xmlns:LocaTime="xalan://org.joda.time.LocalTime"
    xmlns:LocaDate="xalan://org.joda.time.LocalDate">

    <xsl:output method="xml" encoding="utf-8" indent="yes" />

    <xsl:param name="xml-input" as="xs:string" />
    <xsl:param name="xml-input-data" select="document($xml-input)" />

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

    <xsl:template match="*" name="init-element-value">
        <xsl:element name="{name()}">
            <xsl:value-of select="$xml-input-data/{@selectValFrm}"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*" name="init-attribute-value">
        <xsl:attribute name="{name()}">
            <xsl:value-of select="$xml-input-data/{how to resolve attribute value}"/>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

不工作,不知道如何实现这个结果?

2 个答案:

答案 0 :(得分:2)

如果 - 看起来 - 你使用Xalan作为XSLT处理器,你可以使用EXSLT dyn:evaluate()扩展函数来评估给定的字符串作为XPath表达式。试试例如:

XSLT 1.0 + EXSLT

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

<xsl:param name="data-url" select="'data1.xml'"/>

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

<xsl:template match="@selectValFrm">
    <xsl:variable name="path" select="." />
    <xsl:for-each select="document($data-url)">
        <xsl:value-of select="dyn:evaluate($path)"/>
    </xsl:for-each>
</xsl:template>

<xsl:template match="@*">
    <xsl:attribute name="{name()}">
        <xsl:variable name="path" select="." />
        <xsl:for-each select="document($data-url)">
            <xsl:value-of select="dyn:evaluate($path)"/>
        </xsl:for-each>
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

为了实际产生预期结果,您的输入文档(data2.xml)需要按照Martin Honnen的回答进行修改。

答案 1 :(得分:1)

如果您可以使用Saxon 9.7(也可能是9.6)PE或EE,那么您可以使用XSLT 3.0和xsl:evaluate,这是一个例子:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  version="3.0">

    <xsl:param name="xml-input" as="xs:string" select="'test201512150101.xml'"/>
    <xsl:param name="xml-input-data" select="document($xml-input)" />

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

    <xsl:template match="*[@selectValFrm]">
      <xsl:copy>
        <xsl:apply-templates select="@* except @selectValFrm"/>
        <xsl:value-of>
          <xsl:evaluate xpath="@selectValFrm" context-item="$xml-input-data"/>
        </xsl:value-of>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="@num">
      <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
        <xsl:evaluate xpath="." context-item="$xml-input-data"/>
      </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

如果输入文件是

<result>
    <ChildOneDesc selectValFrm="inputRoot/childOne"></ChildOneDesc>
    <ChildTwoDesc>
        <value num="inputRoot/childTwo/nestedChild/@id" selectValFrm="inputRoot/childTwo/nestedChild"></value>
    </ChildTwoDesc> 
</result>

(注意我必须将XPath值更改为以inputRoot而不是root开头),参数文档为

<inputRoot>
    <childOne>
        I am first child
    </childOne>
    <childTwo>
        <nestedChild id="1">
            I am second child
        </nestedChild>
    </childTwo> 
</inputRoot>

然后结果是

<result>
    <ChildOneDesc>
        I am first child
    </ChildOneDesc>
    <ChildTwoDesc>
        <value num="1">
            I am second child
        </value>
    </ChildTwoDesc>
</result>

其他XSLT处理器可能提供扩展功能或指令来使用XPath评估,我们需要知道您使用的处理器,使用as="xs:string"表示您使用的是XSLT 2.0处理器。