【问题标题】:Nested for-each for double matching嵌套 for-each 以实现双重匹配
【发布时间】:2016-09-01 19:39:19
【问题描述】:

我正在努力为我所面临的问题找到正确的方法。
我需要更新'xml1'的'color'节点,使用'xml2'中产品元素的属性'colorDef'

'xml1'和'xml2'通过两个xml中存在的'prodId'属性匹配(选项:多对多),但还有额外的要求:

我只需要更新特定的 'citem'(不是全部),需要更新 'citem' 元素,其中子元素 'type' 等于 'FavType' 元素。

xml1:

<?xml version="1.0" encoding="utf-8"?>
<Products>
    <Product prodId="390">
        <FavType>XX2</FavType>
        <citem>
            <type>XX1</type>
            <color>Green</color>
        </citem>
        <citem>
            <type>XX2</type>
            <color>Blue</color>
        </citem>
        <citem>
            <type>XX3</type>
            <color>Red</color>
        </citem>
    </Product>
</Products>

xml2:

<?xml version="1.0" encoding="utf-8"?>
<OrderCatalog>
    <Product prodId="390">
        <Item colorDef='Yellow'>Tusk</Item>     
    </Product>
    <Product prodId="500">      
        <Item colorDef='Yellow'>Dowel</Item>        
    </Product>
</OrderCatalog>

需要的输出:

<?xml version="1.0" encoding="utf-8"?>
<Products>
    <Product prodId="390">
        <FavType>XX2</FavType>
        <citem>
            <type>XX1</type>
            <color>Green</color>
        </citem>
        <citem>
            <type>XX2</type>
            <color>Yellow</color>
        </citem>
        <citem>
            <type>XX3</type>
            <color>Red</color>
        </citem>
    </Product>
</Products>

目前解决第一个要求的代码:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>


    <xsl:param name="f1" select="'xml20.xml'"/>
    <xsl:variable name="doc1" select="document($f1)"/>

    <xsl:key name="k1" match="OrderCatalog/Product" use="@prodId"/>

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

    <xsl:template match="Products/Product/citem" >
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:variable name="prodId" select="../@prodId"/>
            <xsl:for-each select="$doc1">
                <color>
                    <xsl:value-of select="key('k1', $prodId)/Item/@colorDef"/>
                </color>
            </xsl:for-each>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

首选的解决方案是什么? 为每个嵌套?

更新: 来自以下答案的新 XSL:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>


    <xsl:param name="f1" select="'x20.xml'"/>
    <xsl:variable name="doc1" select="document($f1)"/>

    <xsl:key name="k1" match="OrderCatalog/Product" use="@prodId"/>

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

   <xsl:template match="Products/Product/citem[type=../FavType]/color" >
    <xsl:copy>

        <xsl:variable name="prodId" select="../../@prodId"/>
        <xsl:for-each select="$doc1">
            <xsl:value-of select="key('k1', $prodId)/Item/@colorDef"/>
        </xsl:for-each>

    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

如果 xml1 中的 prodid 在 xml2 中不存在,我会得到这个:

 <citem>
     <type>XX2</type>
     <color/>
  </citem>

而不是原来的

  <citem>
            <type>XX2</type>
            <color>Blue</color>
  </citem>

【问题讨论】:

    标签: xml xslt xslt-1.0


    【解决方案1】:

    我需要更新“xml1”的“color”节点,属性“colorDef”为 'xml2' 中的产品元素

    如果你只想更新color,为什么不让模板直接匹配它而不是它的父citem

    <xsl:template match="Products/Product/citem[type=../FavType]/color" >
        <xsl:copy>
            <xsl:variable name="prodId" select="../../@prodId"/>
            <xsl:for-each select="$doc1">
                <xsl:value-of select="key('k1', $prodId)/Item/@colorDef"/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    

    【讨论】:

    • 我的错,一如既往,为了简单起见,我提供了基本示例。但实际上,我将更新 citem 下的几个元素,当然我可以重复上面的方法,但这不会有效率。
    • "我将更新 citem 下的几个元素," 那么?也为他们制作模板。或者,如果您愿意,可以为特定的 citem 制作一个模板(只需从上面的匹配模式中删除 /color 部分),然后从那里处理孩子。
    • 这个还是有问题的,如果xml2中没有匹配的prodId,那么匹配'FavType'的'color'元素就被删除了!为什么会这样??
    • 恐怕无法重现这个问题。如果xml2.xml 中没有匹配的prodId,则匹配的color 元素仍将被复制,尽管其字符串值为空。
    • 好吧,你的输出中有&lt;color/&gt;,所以你不能说color元素被删除了。 -- 至于为什么会这样,是因为你要求&lt;xsl:value-of select="key('k1', $prodId)/Item/@colorDef"/&gt;,当没有匹配的键时返回一个空字符串。如果您想在这种情况下保留原始值,则必须使用xsl:choose 并首先测试是否存在匹配键。然后决定是要查找的值还是现有的值。
    猜你喜欢
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 2020-03-18
    • 2019-05-21
    • 2013-10-20
    • 2023-01-11
    • 2016-05-19
    • 1970-01-01
    相关资源
    最近更新 更多