2017-06-21 94 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元素。