XSLT 2.0 - 按语言/区域设置层次结构和内容过滤节点



使用 XSLT 2.0,如何根据以下规则/要求动态处理 XML 文档以删除具有 xml:lang 属性的节点?

要求:

  • 查找具有属性xml:lang的任何节点(它是相同类型的直系兄弟姐妹)
  • 请注意,xml:lang值具有基于语言/区域设置的 3 层层次结构,下面提供了非详尽的示例:
    1. X 默认值(第 1 层,最高)
    2. en (第 2 层,语言前缀,其他值示例:fr、es、ru)
    3. en-US(第 3 层,语言前缀后跟后缀,其他值示例:en-GB、en-CA)
  • 根据已知的层次结构,应删除重复值。
  • 删除重复项时,还要考虑同级可能存在的其他属性。
  • 保持 XML 文档的其余部分不受干扰

示例数据集:

<?xml version="1.0" encoding="UTF-8"?>
<arbitrarydepth>
<scenario1 xml:lang="x-default">A Default Node Value</scenario1>
<scenario1 xml:lang="en">A Default Node Value</scenario1>
<scenario1 xml:lang="en-US">A Default Node Value</scenario1>
<scenario2 xml:lang="x-default">The orig value</scenario2>
<scenario2 xml:lang="en">The orig value</scenario2>
<scenario2 xml:lang="en-US">A new value</scenario2>
<scenario3 xml:lang="x-default">The orig value</scenario3>
<scenario3 xml:lang="en">A new value</scenario3>
<scenario3 xml:lang="en-US">The orig value</scenario3>
<scenario4 xml:lang="x-default">The orig value</scenario4>
<scenario4 xml:lang="en">An english value</scenario4>
<scenario4 xml:lang="en-US">An english US value</scenario4>
<scenario4 xml:lang="fr">A french value</scenario4>
<scenario4 xml:lang="fr-FR">A french value</scenario4>
<scenario4 xml:lang="fr-CA">A french Canada value</scenario4>
<scenario5 xml:lang="x-default" attr0="something here">The orig value</scenario5>
<scenario5 xml:lang="en" attr1="Some attribute">The orig value</scenario5>
<scenario5 xml:lang="en-US" attr2="some other attribute">The orig value</scenario5>
<scenario5 xml:lang="fr" attr0="something here">The orig value</scenario5>
<scenario5 xml:lang="fr-FR">The orig value</scenario5>
</arbitrarydepth>

示例结果集:

<?xml version="1.0" encoding="UTF-8"?>
<arbitrarydepth>
<scenario1 xml:lang="x-default">A Default Node Value</scenario1>
<scenario2 xml:lang="x-default">The orig value</scenario2>
<scenario2 xml:lang="en-US">A new value</scenario2>
<scenario3 xml:lang="x-default">The orig value</scenario3>
<scenario3 xml:lang="en">A new value</scenario3>
<scenario3 xml:lang="en-US">The orig value</scenario3>
<scenario4 xml:lang="x-default">The orig value</scenario4>
<scenario4 xml:lang="en">An english value</scenario4>
<scenario4 xml:lang="en-US">An english US value</scenario4>
<scenario4 xml:lang="fr">A french value</scenario4>
<scenario4 xml:lang="fr-CA">A french Canada value</scenario4>
<scenario5 xml:lang="x-default" attr0="something here">The orig value</scenario5>
<scenario5 xml:lang="en" attr1="Some attribute">The orig value</scenario5>
<scenario5 xml:lang="en-US" attr2="some other attribute">The orig value</scenario5>
</arbitrarydepth>

这应该满足所有要求,除了最后一个关于匹配动态属性的要求:

<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*">
    <xsl:variable name="elementName" select="name()"/>
    <xsl:variable name="contentText" select="normalize-space(.)"/>
    <xsl:choose>
        <xsl:when test="not(@xml:lang)">
            <!-- Non-lang element -->
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:apply-templates select="*"/>
            </xsl:copy>
        </xsl:when>
        <xsl:when test="@xml:lang='x-default'">
            <!-- Tier 1: xml:lang="x-default" -->
            <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:when test="contains(@xml:lang,'-')">
            <!-- Tier 3: xml:lang="en-US" -->
            <xsl:variable name="baselang" select="substring-before(@xml:lang, '-')"/>
            <xsl:choose>
                <xsl:when test="../*[name()=$elementName][@xml:lang=$baselang][normalize-space(.)=$contentText]">
                    <!-- Same text as Tier 2 parent -->
                </xsl:when>
                <xsl:when test="../*[name()=$elementName][@xml:lang=$baselang]">
                    <xsl:copy-of select="."/>
                </xsl:when>
                <xsl:when test="../*[name()=$elementName][@xml:lang='x-default'][normalize-space(.)=$contentText]">
                    <!-- Same text as Tier 1 parent -->
                </xsl:when>
                <xsl:when test="../*[name()=$elementName][@xml:lang='x-default']">
                    <xsl:copy-of select="."/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
            <!-- Tier 2: xml:lang="en" -->
            <xsl:choose>
                <xsl:when test="../*[name()=$elementName][@xml:lang='x-default'][normalize-space(.)=$contentText]">
                    <!-- Same text as Tier 1 parent -->
                </xsl:when>
                <xsl:when test="../*[name()=$elementName][@xml:lang='x-default']">
                    <xsl:copy-of select="."/>
                </xsl:when>
                <xsl:otherwise>
                    <!-- No matching parent -->
                    <xsl:copy-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>

演示:http://www.xsltcake.com/slices/uopn40

匹配父属性和子属性之间的动态属性实际上非常复杂。您必须循环遍历属性并与当前父级进行比较。如果父级上缺少任何属性,或者其值不同,则必须保留新元素。

为了满足最后一个要求,我认为你必须转向命令式语言(C#,JavaScript,Java)。

最新更新