2014-09-30 56 views
1

我試圖將一對XML文件中的子項複製到另一個XML文件中。我創建了一個適用於指定元素的白名單,但當我嘗試限制同時也是子項的單個屬性名稱值對時,我找不到匹配項。XSLT複製受限於屬性值對

示例XML:

<?xml version="1.0" encoding="UTF-8"?> 
<catalog catalog-id="Primary"> 
    <product product-id="COLAKIT"> 
     <ean/> 
     <upc/> 
     <unit>SKU</unit> 
     <custom-attributes> 
      <custom-attribute attribute-id="Base_Color">Brown</custom-attribute> 
      <custom-attribute attribute-id="Shipping_Cost">0.0</custom-attribute> 
      <custom-attribute attribute-id="showEstimatedDelivery">false</custom-attribute> 
     </custom-attributes> 
     <classification-category>Kitchen_Housewares-Coffee_and_Tea</classification-category> 
    </product> 

    <product product-id="COLONIAL-48-M-K"> 
     <ean/> 
     <upc/> 
     <unit>SKU</unit> 
     <custom-attributes> 
      <custom-attribute attribute-id="Base_Color">Coffee</custom-attribute> 
      <custom-attribute attribute-id="Shipping_Cost">0.0</custom-attribute> 
      <custom-attribute attribute-id="showEstimatedDelivery">false</custom-attribute> 
     </custom-attributes> 
     <classification-category>Outdoor_Living-Heaters-Fireplaces</classification-category> 
    </product> 

</catalog> 

XSLT:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="some:ns"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

<ns:WhiteList> 
    <name>classification-category</name> 
    <name>custom-attribute[attribute-id()='Shipping_Cost']</name> 
</ns:WhiteList> 

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

<xsl:template match="*[not(descendant-or-self::*[name()=document('')/*/ns:WhiteList/*])]"/> 
</xsl:stylesheet> 

此外,主XML具有節點的100S,我只想要3這是爲什麼我想白名單,而不是排斥。請讓我知道我缺少的屬性=值匹配。

回答

1

嗯,當然,你在上面使用的嘗試不因爲您的源文檔沒有名稱爲custom-attribute[attribute-id()='Shipping_Cost']的任何元素(另外,沒有名稱爲attribute-id()的XPath函數)。

標準XSLT 1.0無法根據XML中存在的字符串值來評估XPath,因此我認爲您可能需要採取一種比您希望的方式稍微不那麼通用的方法。這裏有一種方法:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="some:ns"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

<ns:WhiteList> 
    <element>classification-category</element> 
    <attributeId>Shipping_Cost</attributeId> 
</ns:WhiteList> 
<xsl:variable name="whiteList" select="document('')/*/ns:WhiteList" /> 

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

<xsl:template match="*[not(descendant-or-self::*[name()=$whiteList/element] or 
          (descendant-or-self::custom-attribute/@attribute-id = 
          $whiteList/attributeId) 
          )]"/> 
</xsl:stylesheet> 
+0

謝謝。這很好。我很感激幫助。對字符串XPath有意義 – Curtis 2014-09-30 15:19:47

1

您的方法的問題是,"custom-attribute[attribute-id()='Shipping_Cost']"不是名稱。它甚至不是(在你的情況下)一個XPath表達式;這是一個字符串 - 你需要一個擴展函數(或XSLT 3.0)到評估它作爲XPath。並且您必須對其進行更改才能評估爲有效的 XPath,即使用@attribute-id而不是attribute-id()

您的方法更大的問題是它效率非常低。在XSLT中,明確表示是值得的,特別是如果你談論的是數百個節點。如果不建立「方路」名字的白名單,可以考慮一個更直接的方法:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

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

<!-- "white list" --> 
<xsl:template match="product"> 
    <xsl:copy> 
     <xsl:copy-of select="@product-id"/> 
     <xsl:copy-of select="classification-category"/> 
     <xsl:copy-of select="custom-attributes/custom-attribute[@attribute-id='Shipping_Cost']"/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 
0

可以處理XSLT 1.0中的排序動態評估,但它會涉及到兩個轉換。它利用了XSLT是格式良好的XML這一事實,這意味着您可以使用XSLT將其轉換爲其他XSLT。一個「XSLT寫你自己」的案例。

的想法是你有一個預處理步驟,以當前的XSLT轉換XSLT的新改進版,包括你的「動態」的表達式,然後您可以應用到你的XML:

你會開始通過改變當前的XSLT這樣的:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="some:ns"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

<ns:WhiteList> 
    <name>classification-category</name> 
    <name>custom-attribute[@attribute-id = 'Shipping_Cost']</name> 
</ns:WhiteList> 

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

對於變換的第一個「前處理」步驟中,您將有一個由身份模板的XSLT,而且還匹配xsl:styleheet其複製它的模板,而且還增加了一個新的xsl:template指令,其match屬性w從信息的ns:WhiteList

這裏建立起來是這樣的預處理XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:xslOut="xlst.temp" xmlns:ns="some:ns"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes" /> 

    <xsl:namespace-alias stylesheet-prefix="xslOut" result-prefix="xsl"/> 

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

      <xslOut:template> 
       <xsl:attribute name="match"> 
        <xsl:text>*[</xsl:text> 
        <xsl:for-each select="ns:WhiteList/name"> 
         <xsl:if test="position() > 1"> and </xsl:if> 
         <xsl:text>not(descendant-or-self::</xsl:text> 
         <xsl:value-of select="." /> 
         <xsl:text>)</xsl:text> 
        </xsl:for-each> 
        <xsl:text>]</xsl:text> 
       </xsl:attribute> 
      </xslOut:template> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ns:WhiteList" /> 

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

注意使用xsl:namespace-alias它用在這裏字面輸出XSLT元素(如果你試圖用<xsl:template>更換<xslOut:template>那會導致錯誤。

當預處理XSLT應用到初始XSLT,這個修改XSLT產生

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:ns="some:ns" 
       version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="*[not(descendant-or-self::classification-category) and not(descendant-or-self::custom-attribute[@attribute-id = 'Shipping_Cost'])]"/> 
</xsl:stylesheet> 

然後,您可以將此生成的XSLT對XML,輸出如下:

<catalog catalog-id="Primary"> 
    <product product-id="COLAKIT"> 
     <custom-attributes> 
     <custom-attribute attribute-id="Shipping_Cost">0.0</custom-attribute> 
     </custom-attributes> 
     <classification-category>Kitchen_Housewares-Coffee_and_Tea</classification-category> 
    </product> 
    <product product-id="COLONIAL-48-M-K"> 
     <custom-attributes> 
     <custom-attribute attribute-id="Shipping_Cost">0.0</custom-attribute> 
     </custom-attributes> 
     <classification-category>Outdoor_Living-Heaters-Fireplaces</classification-category> 
    </product> 
</catalog>