【问题标题】:XSLT - transform two different XML files into one without duplication of elementsXSLT - 将两个不同的 XML 文件转换为一个而不重复元素
【发布时间】:2013-03-21 22:14:37
【问题描述】:

我有两个不同的 XML 文件:movies.xml 和亚马逊产品广告 API XML

这是我的 XSLT 文件,它可以转换两个 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2011-08-01"
exclude-result-prefixes="aws">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

<xsl:template match="/">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="h2">Movies list</xsl:element>
        </xsl:element>
        <xsl:element name="body">
            <xsl:apply-templates select="/movies/movie"/>
            <xsl:apply-templates select="aws:ItemLookupResponse/aws:Items/aws:Item/aws:ItemAttributes/aws:Title"/>
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="movie">
    <xsl:element name="a">
        <xsl:attribute name="href">movie_details.php?movieID=<xsl:value-of select="@movieID"/></xsl:attribute>
        <xsl:value-of select="title"/>
    </xsl:element>
    <xsl:element name="br" />
</xsl:template>

<xsl:template match="aws:Title">
    <xsl:element name="h2">Amazon Movie 1</xsl:element>
    <xsl:value-of select="." />
</xsl:template>

</xsl:stylesheet>

apply-templates select="/movies/movie - 从 movies.xml 加载一个包含 5 个电影标题的列表并将它们显示为超链接。

apply-templates select="aws:ItemLookupResponse/aws:Items/aws:Item/aws:ItemAttributes/aws:Title" - 从 Amazon API xml 文件加载电影标题并将其显示为纯文本。

这是我的 HTML 输出:

<html>
  <head>
    <h2>Movies list</h2>
  </head>
  <body>
    <a href="movie_details.php?movieID=1">The Dark Knight Rises</a>
    <br/>
    <a href="movie_details.php?movieID=2">Lawless</a>
    <br/>
    <a href="movie_details.php?movieID=3">Inception</a>
    <br/>
    <a href="movie_details.php?movieID=4">Looper</a>
    <br/>
    <a href="movie_details.php?movieID=5">Django Unchained</a>
    <br/>
  </body>
</html>
<html>
  <head>
    <h2>Movies list</h2>
  </head>
  <body><h2>Amazon Movie 1</h2>Dark Knight Rises [Blu-ray] [2012] [US Import]</body>
</html>

如您所见,这两个模板显示在单独的 HTML 标记中,这导致两个模板的 Head 元素“电影列表”显示两次。

如果我能以某种方式将这两个模板放入一个 HTML 元素中,那么就不会重复任何内容。我尝试了几种方法,但还没有成功。

这是我的 PHP 文件,它创建了两个 XML 文件和一个 XSLT 样式表。它还会生成亚马逊产品的签名 URL。

include('aws_signed_request.php');

$public_key = 'XXXXXXXXXXXXXXXXXXXXXX';
$private_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$associate_tag = 'xxxxxxxxxxxxxxxxxxxxxxx';

// generate signed URL
$request = aws_signed_request('co.uk', array(
        'Operation' => 'ItemLookup',
        'ItemId' => 'B004LWZWGK',
        'ResponseGroup' => 'Small'), $public_key, $private_key, $associate_tag);

// do request (you could also use curl etc.)
$response = @file_get_contents($request);
if ($response === FALSE) {
    echo "Request failed.\n";
} else {

    // parse XML
    $xml = new DOMDocument();
    $xml->load('movies.xml');

    $xml2 = new DOMDocument();
    $xml2->loadXML($response);

    $xsl = new DOMDocument;
    $xsl->load('movies_list.xsl');

    $proc = new XSLTProcessor();
    $proc->importStyleSheet($xsl);

    echo $proc->transformToXML($xml);
    echo $proc->transformToXML($xml2);

}

movies.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="index.xsl"?>
<movies
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="movies.xsd">

<movie movieID="1">
    <title>The Dark Knight Rises</title>
</movie>

<movie movieID="2">
    <title>Lawless</title>
</movie>

<movie movieID="3">
    <title>Inception</title>
</movie>

<movie movieID="4">
    <title>Looper</title>
</movie>

<movie movieID="5">
    <title>Django Unchained</title>
</movie>
</movies>

亚马逊产品广告 API XML

<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
   <OperationRequest>
       <HTTPHeaders>
          <Header Name="UserAgent" Value="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22"/>
       </HTTPHeaders>
       <RequestId>a1138e89-4335-4650-80f2-641e3c58b623</RequestId>
       <Arguments>
    <Argument Name="Operation" Value="ItemLookup"/>
    <Argument Name="Service" Value="AWSECommerceService"/>
    <Argument Name="Signature" Value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
    <Argument Name="AssociateTag" Value="xxxxxxxxxxxxxx"/>
    <Argument Name="Version" Value="2011-08-01"/>
    <Argument Name="ItemId" Value="B004LWZWGK"/>
    <Argument Name="AWSAccessKeyId" Value="xxxxxxxxxxxxxxxxxxxx"/>
    <Argument Name="Timestamp" Value="2013-03-21T13:56:55.000Z"/>
    <Argument Name="ResponseGroup" Value="Small"/>
       </Arguments>
       <RequestProcessingTime>0.0189320000000000</RequestProcessingTime>
       </OperationRequest>
    <Items>
      <Item>
         <ItemAttributes>
           <Title>
            The Dark Knight Rises (Blu-ray/DVD Combo+UltraViolet Digital Copy)
           </Title>
         </ItemAttributes>
      </Item>
    </Items>
</ItemLookupResponse>

浏览器输出:

.

【问题讨论】:

  • Alex,显示两个 XML 文件的一些 sn-ps...
  • 我已经用 XML 文件更新了我的帖子

标签: php xml xslt transform


【解决方案1】:

我无法重现问题

使用您的 XSLT 代码(稍微更改为通过调用 document() 函数访问“movies.xml”):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2011-08-01"
exclude-result-prefixes="aws">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

<xsl:variable name="vMoviesDoc" select=
 "document('file:///c:/temp/delete/movies.xml')"/>

<xsl:template match="/">
    <xsl:element name="html">
        <xsl:element name="head">
            <xsl:element name="h2">Movies list</xsl:element>
        </xsl:element>
        <xsl:element name="body">
            <xsl:apply-templates select="$vMoviesDoc/movies/movie"/>
            <xsl:apply-templates select="aws:ItemLookupResponse/aws:Items/aws:Item/aws:ItemAttributes/aws:Title"/>
        </xsl:element>
    </xsl:element>
</xsl:template>

<xsl:template match="movie">
    <xsl:element name="a">
        <xsl:attribute name="href">movie_details.php?movieID=<xsl:value-of select="@movieID"/></xsl:attribute>
        <xsl:value-of select="title"/>
    </xsl:element>
    <xsl:element name="br" />
</xsl:template>

<xsl:template match="aws:Title">
    <xsl:element name="h2">Amazon Movie 1</xsl:element>
    <xsl:value-of select="." />
</xsl:template>

</xsl:stylesheet>

应用于提供的亚马逊产品广告 API XML 文档时:

<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
   <OperationRequest>
       <HTTPHeaders>
          <Header Name="UserAgent" Value="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22"/>
       </HTTPHeaders>
       <RequestId>a1138e89-4335-4650-80f2-641e3c58b623</RequestId>
       <Arguments>
    <Argument Name="Operation" Value="ItemLookup"/>
    <Argument Name="Service" Value="AWSECommerceService"/>
    <Argument Name="Signature" Value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
    <Argument Name="AssociateTag" Value="xxxxxxxxxxxxxx"/>
    <Argument Name="Version" Value="2011-08-01"/>
    <Argument Name="ItemId" Value="B004LWZWGK"/>
    <Argument Name="AWSAccessKeyId" Value="xxxxxxxxxxxxxxxxxxxx"/>
    <Argument Name="Timestamp" Value="2013-03-21T13:56:55.000Z"/>
    <Argument Name="ResponseGroup" Value="Small"/>
       </Arguments>
       <RequestProcessingTime>0.0189320000000000</RequestProcessingTime>
       </OperationRequest>
    <Items>
      <Item>
         <ItemAttributes>
           <Title>
            The Dark Knight Rises (Blu-ray/DVD Combo+UltraViolet Digital Copy)
           </Title>
         </ItemAttributes>
      </Item>
    </Items>
</ItemLookupResponse>

并在本地目录“C:\temp\delete”中拥有提供的 XML 文档(文件“movies.xml”):

<movies xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="movies.xsd">
    <movie movieID="1">
        <title>The Dark Knight Rises</title>
    </movie>
    <movie movieID="2">
        <title>Lawless</title>
    </movie>
    <movie movieID="3">
        <title>Inception</title>
    </movie>
    <movie movieID="4">
        <title>Looper</title>
    </movie>
    <movie movieID="5">
        <title>Django Unchained</title>
    </movie>
</movies>

转换产生以下结果,其中head 没有重复:

<html>
   <head>
      <h2>Movies list</h2>
   </head>
   <body>
      <a href="movie_details.php?movieID=1">The Dark Knight Rises</a>
      <br/>
      <a href="movie_details.php?movieID=2">Lawless</a>
      <br/>
      <a href="movie_details.php?movieID=3">Inception</a>
      <br/>
      <a href="movie_details.php?movieID=4">Looper</a>
      <br/>
      <a href="movie_details.php?movieID=5">Django Unchained</a>
      <br/>
      <h2>Amazon Movie 1</h2>
            The Dark Knight Rises (Blu-ray/DVD Combo+UltraViolet Digital Copy)
           </body>
</html>

【讨论】:

  • 感谢您的回复,Dimitre。我已经仔细检查了所有内容,但我仍然得到每个包含 head 元素的 html 元素的副本。我认为我的 PHP 代码导致了问题,因为我正在创建和回显两个单独的 xml 文件。它们可能相互重叠并导致所有 html 标签重复。我已经用我的浏览器显示的图像更新了我的帖子。
  • @Alex,我已经使用我正在使用的所有 11 个不同的 XSLT 处理器运行了这个答案的转换——它们都产生了相同的正确结果。如果您使用的是兼容的 XSLT 处理器,那么唯一的原因可能是至少一个 XML 文档或转换本身与此答案中使用的不同。
  • @Alex,在使用document() 添加对“movies.xml”的访问后,您是否从您的PHP 中删除了echo $proc-&gt;transformToXML($xml);?您正在运行 2 个单独的转换。您只需要在“$response”XML 上运行转换。
  • 我通过在 XSLT 中将movies.xml 作为文档加载并删除“$xml = new DOMDocument();”解决了这个问题"$xml->load('movies.xml');"和“回声 $proc->transformToXML($xml);”我的 PHP 代码中的行。现在所有内容都显示在一个 html 元素中,没有任何重复的标签。感谢 Dimitre 和 Daniel 的帮助!
【解决方案2】:

XSLTProcessor 似乎不允许您将 XML 内容设置为参数(setParameter 函数只接受一个字符串),因此您需要使用 XSLT document 函数来处理多个输入文档,如讨论了herehere。您需要将来自 Amazon 的响应保存为文件系统中的文件,然后您的 XSLT 可能看起来像这样(我在其中简化了您的文件名):

<xsl:variable name="amazon" select="document('amazon.xml')"/>

<xsl:template match="/">
    <html>
        <body>
            <h2>Movies List</h2>
            <xsl:apply-templates select="movies/movie" />
            <h2>
                <xsl:value-of select="normalize-space($amazon/aws:ItemLookupResponse/aws:Items/aws:Item/aws:ItemAttributes/aws:Title)"/>
            </h2>
        </body>
    </html>
</xsl:template>

<xsl:template match="movie">
    <a>
        <xsl:attribute name="href">movie_details.php?movieID=<xsl:value-of select="@movieID"/></xsl:attribute>
        <xsl:value-of select="title"/>
    </a>
    <br/>
</xsl:template>

编辑:根据您的 cmets 将代码修改为我的原始答案,并删除了有关“多对一”问题的语言。

【讨论】:

  • 感谢您的回复,Jollymorphic。我已经应用了您的解决方案,但不幸的是,我仍然收到重复的“电影列表”h2 标签。也许我没有正确解释我的问题,但我想要的只是显示“电影列表”标题文本,然后是 5 个超链接电影标题的列表,然后是下面的“黑暗骑士亚马逊电影标题”。我不想在 5 部电影标题和亚马逊标题之间建立任何关系,我只是想在我的电影列表页面中包含 amazon api,看看它是如何工作的。我想要的只是将它显示在一个 HTML 标记中,并且没有重复的“电影列表”标题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多