2017-06-21 101 views
0

我有两个xml结构中需要合并的两个变量。我试图在stackoverflow上基于不同的awnsers编写XSLT样式表,但是我没有成功。XSLT合并两个XML结构

第一个的结构是这样的:

<root> 
    <content> 
     <text-block> 
      <descriptionHead> 
       Some description text for the text block head. 
      </descriptionHead> 
      <description> 
       Some description text block text. 
      </description> 
     </text-block> 
     <shortDescription> 
      <textHead> 
       Example text for the short description head. 
      </textHead> 
      <textBody> 
       Example text for the short description text body. 
      </textBody> 
     </shortDescription> 
     <longDescription> 
      <textHead> 
       Example text for the long description head. 
      </textHead> 
      <textBody> 
       Example text for the short description text body. 
      </textBody> 
     </longDescription> 
    </content> 
</root> 

,第二个看起来像这样:

<root> 
    <content> 
     <text-block> 
      <descriptionHead> 
       Some text 1. 
      </descriptionHead> 
      <description> 
       Some text 2. 
      </description> 
     </text-block> 
     <shortDescription> 
      <textHead></textHead> 
      <textBody></textBody> 
     </shortDescription> 
     <longDescription> 
      <textHead> 
       Some text 3. 
      </textHead> 
      <textBody></textBody> 
     </longDescription> 
    </content> 
</root> 

正如你在第二个看到有一些遗漏的信息。 在shortDescription中,缺少textHead和textBody的文本,在longDescription中缺少textBody的文本。可能缺少文本,文本或全部文本。 现在我想从第一个xml结构中取出缺失的信息并将它们复制到第二个结构中,并用div标记标记更改。

输出应该看起来像:

<root> 
    <content> 
     <text-block> 
      <descriptionHead> 
       Some text 1. 
      </descriptionHead> 
      <description> 
       Some text 2. 
      </description> 
     </text-block> 
     <shortDescription> 
      <textHead> 
       <div class="merged"> 
        Example text for the short description head. 
       </div> 
      </textHead> 
      <textBody> 
       <div class="merged"> 
        Example text for the short description text body. 
       </div> 
      </textBody> 
     </shortDescription> 
     <longDescription> 
      <textHead> 
       Some text 3. 
      </textHead> 
      <textBody> 
       <div class="merged"> 
        Example text for the short description text body. 
       </div> 
      </textBody> 
     </longDescription> 
    </content> 
</root> 

我可以使用XSLT 2.0该任务。用XSLT做这样的事情有可能吗?

+0

xslt是否过度杀伤?一个简单的应用程序可以完成非常简单.. –

回答

0

如果要合并的元素集是有限的,它可能是更清晰的像,每一个元素明确匹配,然后就复制了从另一个文件中的内容,但如果你想要一个更通用的方法来实现的东西这样,这里有一个选项:

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:local="local" 
    exclude-result-prefixes="local xs"> 

    <xsl:output method="xml" indent="yes"/> 

    <!-- Parse the other XML file and store it in memory. --> 
    <xsl:param name="OTHER" select="doc('input-1.xml')"/> 

    <!-- 
    Given a node in an XML document, get the names of all its ancestor elements 
    and the name of the element itself as a sequence of strings. 

    For example, for root/content/text-block/descriptionHead, this returns: 

    ('root', 'content', 'text-block', 'descriptionHead') 
    --> 
    <xsl:function name="local:lineage" as="xs:string*"> 
    <xsl:param name="ctx" as="node()"/> 

    <xsl:sequence select=" 
     for $a in $ctx/ancestor-or-self::* return xs:string(node-name($a)) 
    "/> 
    </xsl:function> 

    <!-- Match children of content/* that don't have any text content. --> 
    <xsl:template match="content/*/*[not(normalize-space(.))]"> 
    <xsl:variable name="lineage" select="local:lineage(.)"/> 

    <xsl:copy> 
     <div class="merged"> 
     <!-- 
     In the other XML document, find the element with the same "lineage" as 
     the current element and apply the template in this stylesheet that 
     match the text node children of that element. 

     For example, for root/content/text-block/descriptionHead, this 
     apply-templates call applies the template that matches the text inside 
     root/content/text-block/descriptionHead in the other XML file. 

     In this stylesheet, the matching template is the identity template 
     below, which copies elements into the output as is. 
     --> 
     <xsl:apply-templates select=" 
      $OTHER/root/content/*/*[deep-equal(local:lineage(.), $lineage)]/text() 
     "/> 
     </div> 
    </xsl:copy> 
    </xsl:template> 

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

</xsl:stylesheet> 
2

这里是你如何能使用XSLT 3.0(由撒克逊9和Altova的最新版本所支持),并利用xsl:evaluatehttps://www.w3.org/TR/xslt-30/#dynamic-xpath)和path功能(解决它的一个示例https://www.w3.org/TR/xpath-functions-31/#func-path):

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" 
    exclude-result-prefixes="xs math" 
    version="3.0"> 

    <xsl:param name="doc2-uri" as="xs:string" select="'name-of-first-input-in-questions.xml'"/> 
    <xsl:param name="doc2" select="doc($doc2-uri)"/> 

    <xsl:mode on-no-match="shallow-copy"/> 

    <xsl:template match="*[not(has-children())]"> 
     <xsl:copy> 
      <div class="merged"> 
       <xsl:evaluate context-item="$doc2" xpath="path() || '/text()'"></xsl:evaluate> 
      </div> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

请注意,虽然Saxon 9.8 HE支持XSLT 3.0,但不幸只在商业版本中支持xsl:evaluate元素。