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