使用xslt按属性值合并2个或更多xmls?

时间:2013-03-16 09:37:33

标签: xml xslt filter merge

我有以下xml:

<PCstore>
    <StoreList>
        <Store id="001">
            <ItemList>
                <Items laptop="DELL" price="300"/>
                <Items laptop="gateway" price="450"/>
                <Items screen="LG" price="200"/>
            </ItemList>
        </Store>
    </StoreList>
</PCstore>

我必须合并:

<PCstore>
    <StoreList>
        <Store id="002">
            <ItemList>
                <Items laptop="gateway" price="650"/>
                <Items screen="LG" price="200/>
                <Items speakers="sony" price="50"/>
            </ItemList>
        </Store>
    </StoreList>
</PCstore>

欲望输出ifiltering属性(laptop =“gateway”):

<PCstore>
    <StoreList>
        <Store id="001">
            <ItemList>
                <Items laptop="gateway" price="450"/>
            </ItemList>
        </Store>
        <Store id="002">
            <ItemList>
                <Items laptop="gateway" price="650"/>
            </ItemList>
        </Store>
    </StoreList>
</PCstore>

依此类推更多xml3.xml,xml4.xml 等...

我没有我尝试的代码,我在XSLT上有点新鲜,我希望有人可以帮助我。

更新

我尝试了这段代码,但它没有用......

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

  <xsl:template match="Items">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:apply-templates
        select="document('xml2.xml')
              /PCstore/StoreList/Store/ItemList[@id = current()/../@id]
                     /Items[@laptop = current()/@value]/*" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

如果只能使用XSLT1.0,一种方法是将xml文件列表作为参数传递给XSLT。例如:

<xsl:param name="filelist">
   <files>
      <file>xml2.xml</file>
      <!-- We can place here xml3.xml and so on -->
   </files>
</xsl:param>

(因此,在这种情况下,我假设您将XSLT应用于第一个xml1.xml,并且您只传入任何其他文件作为参数)。

但是,在XSLT1.0中,您需要使用扩展函数将此参数作为节点集处理。执行<xsl:for-each select="$filelist/files/file">将导致错误“对变量或参数'文件的引用'必须评估为节点列表。”。因此,您需要使用扩展函数将其转换为node-set。在我的示例中,我将使用Microsoft的示例,但根据您的平台,您可以使用exslt.org/common

在这种情况下,这是完整的XSLT

<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:msxml="urn:schemas-microsoft-com:xslt" 
     extension-element-prefixes="msxml">

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

   <xsl:param name="filelist">
      <files>
         <file>xml2.xml</file>
      </files>
   </xsl:param>

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

   <xsl:template match="StoreList">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
         <xsl:for-each select="msxml:node-set($filelist)/files/file">
            <xsl:apply-templates select="document(text())/PCstore/StoreList/Store"/>
         </xsl:for-each>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="Items[not(@laptop='gateway')]"/>
</xsl:stylesheet>

当应用于XSLT时,输出

<PCstore>
   <StoreList>
      <Store id="001">
         <ItemList>
            <Items laptop="gateway" price="450"/>
         </ItemList>
      </Store>
      <Store id="002">
         <ItemList>
            <Items laptop="gateway" price="650"/>
         </ItemList>
      </Store>
   </StoreList>
</PCstore>

请注意,必须存在文件才能使其正常工作。如果传入不存在的文件名,则会发生错误。

答案 1 :(得分:0)

如果您可以使用XSLT 2.0,则可以使用collection() ...

<强> xml1.xml

<PCstore>
    <StoreList>
        <Store id="001">
            <ItemList>
                <Items laptop="DELL" price="300"/>
                <Items laptop="gateway" price="450"/>
                <Items screen="LG" price="200"/>
            </ItemList>
        </Store>
    </StoreList>
</PCstore>

<强> xml2.xml

<PCstore>
    <StoreList>
        <Store id="002">
            <ItemList>
                <Items laptop="gateway" price="650"/>
                <Items screen="LG" price="200"/>
                <Items speakers="sony" price="50"/>
            </ItemList>
        </Store>
    </StoreList>
</PCstore>

XSLT 2.0

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

    <xsl:param name="type" select="'laptop'"/>
    <xsl:param name="brand" select="'gateway'"/>

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

    <xsl:template match="/">
        <PCstore>
            <StoreList>
                <xsl:apply-templates select="collection('file:///C:/store_test?select=*.xml')/PCstore/StoreList/Store"/>
            </StoreList>
        </PCstore>
    </xsl:template>

    <xsl:template match="Items[not(@*[name()=$type]=$brand)]"/>

</xsl:stylesheet>

<强>输出

<PCstore>
   <StoreList>
      <Store id="001">
            <ItemList>

                <Items laptop="gateway" price="450"/>

            </ItemList>
        </Store>
      <Store id="002">
            <ItemList>
                <Items laptop="gateway" price="650"/>


            </ItemList>
        </Store>
   </StoreList>
</PCstore>