2009-10-20 87 views
1

我试图将XML文件的某些部分转换为另一个XML文件。源文件:XSLT:在该循环之外的循环内使用表达式的结果

<CUSTOMERS> 
    <CUSTOMER> 
    <CUSTOMER_NUMBER>12345678</CUSTOMER_NUMBER> 
    <CUSTOMER_ADDRESS> 
     <CUSTOMER_ADDRESS_NAME>John Doe</CUSTOMER_ADDRESS_NAME> 
     <CUSTOMER_ADDRESS_STREET>Street 1</CUSTOMER_ADDRESS_STREET> 
     <CUSTOMER_ADDRESS_CITY>Amsterdam</CUSTOMER_ADDRESS_CITY> 
    </CUSTOMER_ADDRESS> 
    <CUSTOM_FIELDS> 
     <CUSTOM_FIELD> 
     <CUSTOM_FIELD_NAME>Cellphone</CUSTOM_FIELD_NAME> 
     <CUSTOM_FIELD_VALUE>443209432</CUSTOM_FIELD_VALUE> 
     </CUSTOM_FIELD> 
     <CUSTOM_FIELD> 
     <CUSTOM_FIELD_NAME>Geo</CUSTOM_FIELD_NAME> 
     <CUSTOM_FIELD_VALUE>323932121,31231233,0</CUSTOM_FIELD_VALUE> 
     </CUSTOM_FIELD> 
    </CUSTOM_FIELDS> 
    </CUSTOMER> 
</CUSTOMERS> 

规则:

  • 不是每个CUSTOMERCUSTOM_FIELDS,那些没有CUSTOM_FIELDS谁不应该被处理。
  • CUSTOMERCUSTOM_FIELDS时,所有CUSTOM_FIELDS的数量和顺序可能会有所不同。如果它有一个CUSTOM_FIELD这名字是'Geo'

所以在我的XSL我试图遍历所有CUSTOMERS,以及通过CUSTOM_FIELDS每个CUSTOMER

  • 一个CUSTOMER只应处理。当它找到一个叫做'Geo'的应该输出数据。

    <xsl:for-each select="CUSTOMERS/CUSTOMER"> 
        <xsl:for-each select="CUSTOM_FIELDS/CUSTOM_FIELD"> 
        <xsl:if test=".[CUSTOM_FIELD_NAME='Geo']"> 
         <Placemark> 
         <name> 
          <xsl:value-of select="CUSTOMER_NUMBER" /> 
          <xsl:text> </xsl:text> 
          <xsl:value-of select="CUSTOMER_ADDRESS/CUSTOMER_ADDRESS_NAME" /> 
         </name> 
         <styleUrl>#msn_ylw-pushpin</styleUrl> 
         <Point> 
          <coordinates> 
          <xsl:value-of select="CUSTOM_FIELD_NAME" /> 
          </coordinates> 
         </Point> 
         </Placemark> 
        </xsl:if> 
        </xsl:for-each> 
    </xsl:for-each> 
    

    当然在这一点上我在CUSTOMERS/CUSTOMER/CUSTOM_FIELDS/CUSTOM_FIELD,但因此它不可能从那些几级了节点的输出数据。

    我试着在if块中设置一个变量,然后应该在if块之后读取以查看是否应该返回任何数据,但我知道变量只能设置一次,因此无法使用为此目标。

    所以我的问题是:

    • 我真的需要一个循环,看看是否有CUSTOM_FIELD谁的CUSTOM_FIELD_NAME = 'Geo'
    • 如果需要循环,我如何使用循环内部,循环外部的结果?
    • 或者如果这是不可能的,我该如何从节点上的节点返回值,这些节点比我当前所在的节点高出几级?
  • 回答

    2

    您的问题很容易用XPath解决。考虑这个解决方案:

    <xsl:stylesheet 
        version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    > 
        <xsl:output method="xml" indent="yes" encoding="utf-8" /> 
    
        <xsl:template match="CUSTOMERS"> 
        <Placemarks> 
         <!-- apply templates to every customer --> 
         <xsl:apply-templates select="CUSTOMER" /> 
        </Placemarks> 
        </xsl:template> 
    
        <xsl:template match="CUSTOMER"> 
        <!-- process only customers that have a "Geo" custom field --> 
        <xsl:if test="CUSTOM_FIELDS/CUSTOM_FIELD[CUSTOM_FIELD_NAME = 'Geo']"> 
         <Placemark> 
         <name> 
          <xsl:value-of select="CUSTOMER_NUMBER"/> 
          <xsl:text> </xsl:text> 
          <xsl:value-of select="CUSTOMER_ADDRESS/CUSTOMER_ADDRESS_NAME"/> 
         </name> 
         <styleUrl> 
          <xsl:text>#msn_ylw-pushpin</xsl:text> 
         </styleUrl> 
         <Point> 
          <coordinates> 
          <xsl:value-of select=" 
           CUSTOM_FIELDS/CUSTOM_FIELD[ 
           CUSTOM_FIELD_NAME = 'Geo' 
           ]/CUSTOM_FIELD_VALUE 
          "/> 
          </coordinates> 
         </Point> 
         </Placemark> 
        </xsl:if> 
        </xsl:template> 
    
    </xsl:stylesheet> 
    

    第一个模板(match="CUSTOMERS")处理每个<CUSTOMER>节点。

    他们被交给第二个模板(match="CUSTOMER"),决定是否处理客户。

    它通过检查名称为'Geo'的自定义字段的存在来做到这一点。如果存在这样的节点,则创建<Placemark>。上面的输出是:

    <Placemarks> 
        <Placemark> 
        <name>12345678 John Doe</name> 
        <styleUrl>#msn_ylw-pushpin</styleUrl> 
        <Point> 
         <coordinates>323932121,31231233,0</coordinates> 
        </Point> 
        </Placemark> 
    </Placemarks> 
    

    所以没有需要任何循环或广泛的检查,他们表明你是不是从XSLT的观点看问题。;-)

    我们您的问题:

    [...]使其不能输出从几个 水平,直至节点 数据。

    当然这是 - 您可以随时使用'..' XPath操作员或沿着轴移动ancestor::。我建议你先阅读关于XPath的更多内容,你似乎很想念。

    我试过在 如果块,那么这应该 if区块后读,看是否有数据应 返回,但我明白变量 只能设置一次,所以设置一个变量他们也不能是用于此目标的 。

    变量不只是只读的,如果处理流程离开其父元素,它们也会立即超出范围。因此,检查的变量内部的以外的if块的变量 if-block无法开始。

    我真的需要一个循环来看看 有一个CUSTOM_FIELD谁的 CUSTOM_FIELD_NAME = 'Geo'

    不需要。您需要像上面显示的XPath检查。

    如果需要循环,我怎么能使用 结果从内循环,外 循环?

    否如上所述。

    或者,如果这是不可能的,我怎么能 从在节点之上的 几级我 目前节点的返回值?

    上面还解释过。 ;-)

    +0

    感谢您的正确答案,并深入解释! 我知道必须有一种更有效的方法来实现这一点,但我发现的所有示例和文档仅列出了非常简单的案例。 无论如何,再次感谢:-) – Rene 2009-10-20 13:46:08

    +0

    不客气。 :-) – Tomalak 2009-10-20 14:53:27