簡體   English   中英

XSLT合並兩個XML結構

[英]XSLT Merge two XML structures

我在兩個需要合並的變量中有兩個xml結構。 我嘗試在stackoverflow上基於不同的遮篷編寫XSLT樣式表,但未成功。

第一個的結構如下所示:

<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結構中刪除丟失的信息,並將它們復制到第二個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做類似的事情嗎?

這是一個示例,您可以使用XSLT 3.0(由Saxon 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元素。

如果要合並的元素集受到限制,則可以更明確地匹配每個類似的元素,然后僅復制另一個文件中的內容,但是如果您希望采用更通用的方式來實現類似目的,則可以一種選擇:

<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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM