XSLT - 如何通过外部XML数据过滤数据源?

时间:2015-07-14 09:08:00

标签: xpath internet-explorer-7 xslt-1.0

我有以下XML数据结构:

<root>
    <info>
      <creationDate>2015-03-11 11:45:49</creationDate>
    </info>
    <promotions>
      <promotion>
        <header>
          <id>1</id>
          <name>Name 1</name>
        </header>
        <positions>
              <position>
                <id>1</id>
                <name>Some position name 1</name>
              </position>
              <position>
                <id>2</id>
                <name>Some position name 2</name>
              </position>
          </position>
        </positions>
      </promotion>
      <promotion>
        <header>
          <id>2</id>
          <name>Name 2</name>
        </header>
        <positions>
          <position>
            <id>3</id>
            <name>Some position name 3</name>
          </position>
        </positions>
      </promotion>
    </promotions>
  </root>

用作我的模板的主要数据源,如下所示:

<xsl:template match="root">
...

我需要通过&#34; filter.xml&#34;来过滤上面的内容。文件,包含要过滤掉的促销ID,并且需要使用 IE7 。这样的事情可能吗?

对于初学者,我尝试在 xsl:apply-templates select 语句中找到添加过滤器的方法,以便仅ID = 2的促销将由模板处理但失败了 - 是否有可能写出Xpath,它会说:

&#34;从根节点给我一切,但促销只有Id = 2&#34; ?

感谢。

EDIT1:

对命名空间感到抱歉 - 首先它不应该存在。至于filter.xml - 它尚未明确定义 - 目前,我使用以下内容:

<usedUpPromotions>
  <header>
    <promotionId>
      1
    </promotionId>
  </header>
  <header>
    <promotionId>
      2
    </promotionId>
  </header>
  <header>
    <promotionId>
      3
    </promotionId>
  </header>
</usedUpPromotions>

我想使用类似的东西:

<xsl:apply-templates select="root[hereIsMyWhereId != (document('Load externalXmlHere')/select/IdtoFilterOut)"/>

但我似乎找不到以这种方式过滤数据的方法......

EDIT2:

我会尝试使用代码作为示例进行解释 - 让我们暂时假设我们有以下内容:

XmlData initialXmlData;&lt; - 这是我们过滤前的XML数据

XmlData filter; - &lt;这包含filter.xml数据

Html GenerateHtmlFromTemplate(XmlData initialXmlData) - this is my Xslt template
{
...some precessing here
}

我想修改我的模板以实现以下目标:

Html GenerateHtmlFromTemplate(XmlData initialXmlData, XmlData filter) 
{
XmlData filteredData = data.FilterBy(filter);
...same processing here as above, but use 'filteredData', instead of 'initialXmlData'
}

我希望它现在更清楚:) - 主要问题,看起来我想过滤的Id元素是在数组变量中,所以我不能简单地使用:

在我的主要模板中 - 我绕过了问题,稍后通过过滤for-each循环,但我仍然想知道是否可以简单地告诉模板&#34;从现在开始使用过滤数据,而不是原创&#34;。

EDIT3:

@ michael.hor257k - 为了回答你的问题,我修改了你提供的模板:

Template.xml中:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="#"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ksx="http://www.test.com/test" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xsl:output encoding="utf-8" indent="no" method="html"/>

<root xmlns="http://www.test.com/test">
  <info>
    <creationDate>2015-03-11 11:45:49</creationDate>
  </info>
  <promotions>
    <promotion>
      <header>
        <id atr="tre">1</id>
        <name>Promotion 1</name>
      </header>
      <positions>
        <position>
          <id>1</id>
          <name>Position 1a</name>
        </position>
        <position>
          <id>2</id>
          <name>Position 1b</name>
        </position>
      </positions>
    </promotion>
    <promotion>
      <header>
        <id>2</id>
        <name>Promotion 2</name>
      </header>
      <positions>
        <position>
          <id>3</id>
          <name>Position 2a</name>
        </position>
      </positions>
    </promotion>
  </promotions>
</root>

<xsl:param name="new-path" select="'new.xml'"/>
<xsl:variable name="new-promotions" select="document($new-path)/newPromotions/promotion" />



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

<xsl:template match="ksx:root">
    <xsl:copy>
        <xsl:apply-templates select="ksx:promotions/ksx:promotion[not(ksx:header/ksx:id=$new-promotions/header/id)]"/>
        <xsl:apply-templates select="$new-promotions"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

new.xml:

<?xml version="1.0" encoding="utf-8"?>
<newPromotions>
    <promotion>
      <header>
        <id>2</id>
        <name>New Promotion 2</name>
      </header>
      <positions>
        <position>
          <id>4</id>
          <name>New Position 2A</name>
        </position>
      </positions>
    </promotion>
    <promotion>
      <header>
        <id>3</id>
        <name>New Promotion 3</name>
      </header>
      <positions>
        <position>
          <id>5</id>
          <name>New Position 3A</name>
        </position>
      </positions>
    </promotion>
</newPromotions>

如果您保存这些内容,并在Chrome中打开template.xml,它可以很好地工作 - 但我想要的是过滤掉外部模板节点的数据:

<xsl:template match="ksx:root">

所以,我试过这个:

<xsl:template match="ksx:root[ksx:promotion/ksx:header/ksx:id=1]">

我希望从 root 获取所有数据,但促销过滤到Id = 1的那些 - 但是它提供了所有数据而且没有错误,现在我注意到了这一点:

<xsl:template match="ksx:root[ksx:promotions/ksx:promotion/ksx:header/ksx:id=$new-promotions/header/id]">

导致错误&#34;变量不能在此表达式中使用&#34; - 所以我想,我想要做的事情可能是从模板节点外面做的......?

对于这种困惑感到抱歉 - 我希望现在更清楚了。我只是想将模板节点视为一种方法并且&#34;传递&#34;将数据过滤到它,而不是过滤其中的数据。

Edit4:

在我的具体案例中,我有很多&#34; root&#34;促销数据集,以及包含在处理期间隐藏的促销ID的小型外部XML文件。所以在我的情况下,过滤意味着:&#34;从根元素中取出所有内容,但过滤促销只有那些不在外部文件中的ID才会被处理&#34;。如果我有:

<root xmlns="http://www.test.com/test">
  <info>
    <creationDate>2015-03-11 11:45:49</creationDate>
  </info>
  <someData1>Some data 1</someData1>
  <someData2>Some data 2</someData2>
  <someData3>Some data 3</someData3>
  <promotions>
    <promotion>
      <header>
        <id>1</id>
        <name>Promotion 1</name>
      </header>
      <positions>
        <position>
          <id>1</id>
          <name>Position 1a</name>
        </position>
        <position>
          <id>2</id>
          <name>Position 1b</name>
        </position>
      </positions>
    </promotion>
    <promotion>
      <header>
        <id>2</id>
        <name>Promotion 2</name>
      </header>
      <positions>
        <position>
          <id>3</id>
          <name>Position 2a</name>
        </position>
      </positions>
    </promotion>
    <promotion>
      <header>
        <id>3</id>
        <name>Promotion 3</name>
      </header>
      <positions>
        <position>
          <id>4</id>
          <name>Position 3a</name>
        </position>
      </positions>
    </promotion>
  </promotions>
</root>

并过滤:

<?xml version="1.0" encoding="UTF-8"?>
<usedUpPromotions>
    <id>1</id>
    <id>2</id>
</usedUpPromotions>

然后我希望得到:

<root xmlns="http://www.test.com/test">
  <info>
    <creationDate>2015-03-11 11:45:49</creationDate>
  </info>
  <someData1>Some data 1</someData1>
  <someData2>Some data 2</someData2>
  <someData3>Some data 3</someData3>
  <promotions>
    <promotion>
      <header>
        <id>3</id>
        <name>Promotion 3</name>
      </header>
      <positions>
        <position>
          <id>4</id>
          <name>Position 3a</name>
        </position>
      </positions>
    </promotion>
  </promotions>
</root>

1 个答案:

答案 0 :(得分:1)

要仅处理Id = 2的促销,您可以使用(来自root的上下文):

<xsl:apply-templates select="promotions/promotion[header/id='2']"/>

加了:

以下是一个展示如何合并&#34;您的输入XML与重写的XML文档。给出:

<强> XML

<root>
  <info>
    <creationDate>2015-03-11 11:45:49</creationDate>
  </info>
  <promotions>
    <promotion>
      <header>
        <id>1</id>
        <name>Promotion 1</name>
      </header>
      <positions>
        <position>
          <id>1</id>
          <name>Position 1a</name>
        </position>
        <position>
          <id>2</id>
          <name>Position 1b</name>
        </position>
      </positions>
    </promotion>
    <promotion>
      <header>
        <id>2</id>
        <name>Promotion 2</name>
      </header>
      <positions>
        <position>
          <id>3</id>
          <name>Position 2a</name>
        </position>
      </positions>
    </promotion>
  </promotions>
</root>

<强> new.xml

<newPromotions>
    <promotion>
      <header>
        <id>2</id>
        <name>New Promotion 2</name>
      </header>
      <positions>
        <position>
          <id>4</id>
          <name>New Position 2A</name>
        </position>
      </positions>
    </promotion>
    <promotion>
      <header>
        <id>3</id>
        <name>New Promotion 3</name>
      </header>
      <positions>
        <position>
          <id>5</id>
          <name>New Position 3A</name>
        </position>
      </positions>
    </promotion>
</newPromotions>

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="*"/>

<xsl:param name="new-path" select="'path/to/new.xml'"/>
<xsl:variable name="new-promotions" select="document($new-path)/newPromotions/promotion" />

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

<xsl:template match="promotions">
    <xsl:copy>
        <xsl:apply-templates select="promotion[not(header/id=$new-promotions/header/id)]"/>
        <xsl:apply-templates select="$new-promotions"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

<强>结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <info>
      <creationDate>2015-03-11 11:45:49</creationDate>
   </info>
   <promotions>
      <promotion>
         <header>
            <id>1</id>
            <name>Promotion 1</name>
         </header>
         <positions>
            <position>
               <id>1</id>
               <name>Position 1a</name>
            </position>
            <position>
               <id>2</id>
               <name>Position 1b</name>
            </position>
         </positions>
      </promotion>
      <promotion>
         <header>
            <id>2</id>
            <name>New Promotion 2</name>
         </header>
         <positions>
            <position>
               <id>4</id>
               <name>New Position 2A</name>
            </position>
         </positions>
      </promotion>
      <promotion>
         <header>
            <id>3</id>
            <name>New Promotion 3</name>
         </header>
         <positions>
            <position>
               <id>5</id>
               <name>New Position 3A</name>
            </position>
         </positions>
      </promotion>
   </promotions>
</root>

响应您的编辑#4:

  

所以在我的情况下,过滤意味着:&#34;从根获取所有内容   元素,但筛选促销,所以只有那些ID不在   外部文件,将被处理&#34;。

我上面的回答有两件事:

  1. 它复制来自外部文件中ID 的输入XML文档促销之外的所有内容;
  2. 添加外部文件中列出的所有促销信息。
  3. 如果您只想做#1但不想做#2,那么请更改:

    <xsl:template match="promotions">
        <xsl:copy>
            <xsl:apply-templates select="promotion[not(header/id=$new-promotions/header/id)]"/>
            <xsl:apply-templates select="$new-promotions"/>
        </xsl:copy>
    </xsl:template>
    

    为:

    <xsl:template match="promotions">
        <xsl:copy>
            <xsl:apply-templates select="promotion[not(header/id=$new-promotions/header/id)]"/>
        </xsl:copy>
    </xsl:template>
    

    在给定的示例中,结果将是:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <info>
          <creationDate>2015-03-11 11:45:49</creationDate>
       </info>
       <promotions>
          <promotion>
             <header>
                <id>1</id>
                <name>Promotion 1</name>
             </header>
             <positions>
                <position>
                   <id>1</id>
                   <name>Position 1a</name>
                </position>
                <position>
                   <id>2</id>
                   <name>Position 1b</name>
                </position>
             </positions>
          </promotion>
       </promotions>
    </root>