基于已知 XSL 对未知 XML 进行逆向工程

发布于 2024-09-19 12:53:06 字数 5713 浏览 6 评论 0原文

解决了!

在遵循 Matti 的建议后,我删除了自定义函数,一切都很好。

原始帖子:

从今天起我还是 XSLT 的新手,所以我确信这对你们中的许多人来说是理所当然的。无论如何:

我的任务是为我公司的网站创建一个小部件,该小部件使用第三方供应商提供的数据。

供应商拒绝向我们发送示例 XML 文件(甚至是只有元素标签的空白文件!),因此我尝试根据我在 XSLT 中看到的内容重新创建 XML他们确实派了我们。 (荒谬比比皆是

这是我们发送的(已删除的)XSLT 文件:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:myCustXslFunctions="urn:CustomXslFunctions">

  <xsl:variable name="NumberColumns" >1</xsl:variable>
  <xsl:variable name="PaperId" >1234567890ABCDEF</xsl:variable>

  <xsl:output method="html" version="1.0" encoding="UTF-8" indent="no" />
  <xsl:template match="/NewDataSet">
    <div><xsl:apply-templates select="/NewDataSet" mode="columns" /></div>
  </xsl:template>

  <xsl:template match="NewDataSet" mode="columns">
    <xsl:for-each select="Table[position() mod $NumberColumns  = 1 or $NumberColumns = 1]">
      <p>
        <xsl:for-each select=".|following-sibling::Table[position() &lt; $NumberColumns]">
          <span class="description">
            <xsl:element name="a">
              <xsl:attribute name="target">_blank</xsl:attribute>
              <xsl:attribute name="class" >description</xsl:attribute>
              <xsl:choose>
                <xsl:when test="retail='true'">
                  <xsl:attribute name="href">http://website/retail/?pid=<xsl:value-of select="$PaperId" />&#38;adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:attribute name="href">http://website/?pid=<xsl:value-of select="$PaperId" />&#38;adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:otherwise>
              </xsl:choose>
              <xsl:choose>
                <xsl:when test="imageurl != ''">
                  <xsl:element name="img">
                    <xsl:attribute name="src"><xsl:value-of select="imageurl" /></xsl:attribute>
                    <xsl:attribute name="border">0</xsl:attribute>
                    <xsl:attribute name="class">thumbnail</xsl:attribute>
                  </xsl:element>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:element name="img">
                    <xsl:attribute name="src">http://website/thumbs/<xsl:value-of select="paperid" />_<xsl:value-of select="paperitemid" />_100.jpg</xsl:attribute>
                    <xsl:attribute name="border">0</xsl:attribute>
                    <xsl:attribute name="class">thumbnail</xsl:attribute>
                  </xsl:element>
                </xsl:otherwise>
              </xsl:choose>
              </xsl:element>
          </span>
        </xsl:for-each>
      </p>
      <p>
        <xsl:for-each select=".|following-sibling::Table[position() &lt; $NumberColumns]">
          <span class="description">
            <xsl:element name="a">
              <xsl:attribute name="target">_blank</xsl:attribute>
              <xsl:attribute name="class" >description</xsl:attribute>
              <xsl:choose>
                <xsl:when test="retail='true'">
                  <xsl:attribute name="href">http://website/?pid=<xsl:value-of select="$PaperId" />&#38;adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:attribute name="href">http://website/?pid=<xsl:value-of select="$PaperId" />&#38;adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:otherwise>
              </xsl:choose>
              <xsl:choose>
                <xsl:when test="string-length(shortdescr) = 0"><xsl:value-of select="myCustXslFunctions:MakeNice(descr,20,20,'Left','true')" /></xsl:when>
                <xsl:otherwise><xsl:value-of select="myCustXslFunctions:MakeNice(shortdescr,20,20,'Left','true')" /></xsl:otherwise>
              </xsl:choose>
            </xsl:element>
          </span>
        </xsl:for-each>
      </p>
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

我对 XML 进行逆向工程的无力尝试:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="facepalm.xsl"?>
<NewDataSet>
  <Table>
    <paperid>123</paperid>
    <paperitemid>12345</paperitemid>
    <descr>facepalm of doom</descr>
    <shortdescr>facepalm</shortdescr>
    <retail>true</retail>
    <imageurl>http://website/facepalm.jpg</imageurl>
  </Table>
  <Table>
    <paperid>456</paperid>
    <paperitemid>67890</paperitemid>
    <descr>mega-sigh</descr>
    <shortdescr>sigh</shortdescr>
    <retail>true</retail>
    <imageurl>http://website/sigh.jpg</imageurl>
  </Table>
</NewDataSet>

>毫无疑问,我认为我忽略了一些简单的事情,但我的 XSLT 新手身份已经使这个项目花费了几个小时。

非常感谢任何帮助。

Solved!

After following Matti's suggestions, I removed the custom functions and all is well.

Original Post:

I'm new to XSLT as of today, so I'm sure this is a no-brainer for many of you. Anyways:

I've been tasked with creating a widget for my company's website that uses data provided by a 3rd-party vendor.

The vendor refuses to send us a sample XML file (even a blanked-out one with just the element tags!) so I'm trying to recreate the XML based on what I can see in the XSLT that they -did- send us. (ridiculosity abounds)

This is the (stripped) XSLT file we were sent:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:myCustXslFunctions="urn:CustomXslFunctions">

  <xsl:variable name="NumberColumns" >1</xsl:variable>
  <xsl:variable name="PaperId" >1234567890ABCDEF</xsl:variable>

  <xsl:output method="html" version="1.0" encoding="UTF-8" indent="no" />
  <xsl:template match="/NewDataSet">
    <div><xsl:apply-templates select="/NewDataSet" mode="columns" /></div>
  </xsl:template>

  <xsl:template match="NewDataSet" mode="columns">
    <xsl:for-each select="Table[position() mod $NumberColumns  = 1 or $NumberColumns = 1]">
      <p>
        <xsl:for-each select=".|following-sibling::Table[position() < $NumberColumns]">
          <span class="description">
            <xsl:element name="a">
              <xsl:attribute name="target">_blank</xsl:attribute>
              <xsl:attribute name="class" >description</xsl:attribute>
              <xsl:choose>
                <xsl:when test="retail='true'">
                  <xsl:attribute name="href">http://website/retail/?pid=<xsl:value-of select="$PaperId" />&adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:attribute name="href">http://website/?pid=<xsl:value-of select="$PaperId" />&adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:otherwise>
              </xsl:choose>
              <xsl:choose>
                <xsl:when test="imageurl != ''">
                  <xsl:element name="img">
                    <xsl:attribute name="src"><xsl:value-of select="imageurl" /></xsl:attribute>
                    <xsl:attribute name="border">0</xsl:attribute>
                    <xsl:attribute name="class">thumbnail</xsl:attribute>
                  </xsl:element>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:element name="img">
                    <xsl:attribute name="src">http://website/thumbs/<xsl:value-of select="paperid" />_<xsl:value-of select="paperitemid" />_100.jpg</xsl:attribute>
                    <xsl:attribute name="border">0</xsl:attribute>
                    <xsl:attribute name="class">thumbnail</xsl:attribute>
                  </xsl:element>
                </xsl:otherwise>
              </xsl:choose>
              </xsl:element>
          </span>
        </xsl:for-each>
      </p>
      <p>
        <xsl:for-each select=".|following-sibling::Table[position() < $NumberColumns]">
          <span class="description">
            <xsl:element name="a">
              <xsl:attribute name="target">_blank</xsl:attribute>
              <xsl:attribute name="class" >description</xsl:attribute>
              <xsl:choose>
                <xsl:when test="retail='true'">
                  <xsl:attribute name="href">http://website/?pid=<xsl:value-of select="$PaperId" />&adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:attribute name="href">http://website/?pid=<xsl:value-of select="$PaperId" />&adid=<xsl:value-of select="paperitemid" /></xsl:attribute>
                </xsl:otherwise>
              </xsl:choose>
              <xsl:choose>
                <xsl:when test="string-length(shortdescr) = 0"><xsl:value-of select="myCustXslFunctions:MakeNice(descr,20,20,'Left','true')" /></xsl:when>
                <xsl:otherwise><xsl:value-of select="myCustXslFunctions:MakeNice(shortdescr,20,20,'Left','true')" /></xsl:otherwise>
              </xsl:choose>
            </xsl:element>
          </span>
        </xsl:for-each>
      </p>
    </xsl:for-each>
  </xsl:template>
</xsl:transform>

And my feeble attempt at reverse-engineering the XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="facepalm.xsl"?>
<NewDataSet>
  <Table>
    <paperid>123</paperid>
    <paperitemid>12345</paperitemid>
    <descr>facepalm of doom</descr>
    <shortdescr>facepalm</shortdescr>
    <retail>true</retail>
    <imageurl>http://website/facepalm.jpg</imageurl>
  </Table>
  <Table>
    <paperid>456</paperid>
    <paperitemid>67890</paperitemid>
    <descr>mega-sigh</descr>
    <shortdescr>sigh</shortdescr>
    <retail>true</retail>
    <imageurl>http://website/sigh.jpg</imageurl>
  </Table>
</NewDataSet>

There's no doubt in my mind that I'm overlooking something simple, but my novice status with XSLT has already made this a multi-hour project.

Any help is greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

芸娘子的小脾气 2024-09-26 12:53:06

我的猜测更像是:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="facepalm.xsl"?>
<NewDataSet>
 <Table>
  <paperid>123</paperid>
  <paperitemid>12345</paperitemid>
  <descr>failvendor</descr>
  <shortdescr>facepalm</shortdescr>
  <retail>true</retail>
  <imageurl>http://website/facepalm.jpg</imageurl>
 </Table>
 <Table>
  <paperid>456</paperid>
  <paperitemid>67890</paperitemid>
  <descr>is fail</descr>
  <shortdescr>sigh</shortdescr>
  <retail>true</retail>
  <imageurl>http://website/sigh.jpg</imageurl>
 </Table>
</NewDataSet>
  1. [] 内容并不是指元素名称的一部分,而是指元素的位置。所以元素名称就是Table
  2. 您错过了 descrpaperid 元素。

XSLT 似乎正在做的是将项目按列布置在列表中。是的,XSLT 就是这么复杂。

另外,如果定义了imageurl,它似乎会忽略paperidpaperitemid,如果定义了descr,它似乎会忽略descr提供了>shortdescr。这可能会对您的追求有所帮助。

...顺便说一句,如果没有实际的 XML,您应该如何测试它?

My guess would be more like:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="facepalm.xsl"?>
<NewDataSet>
 <Table>
  <paperid>123</paperid>
  <paperitemid>12345</paperitemid>
  <descr>failvendor</descr>
  <shortdescr>facepalm</shortdescr>
  <retail>true</retail>
  <imageurl>http://website/facepalm.jpg</imageurl>
 </Table>
 <Table>
  <paperid>456</paperid>
  <paperitemid>67890</paperitemid>
  <descr>is fail</descr>
  <shortdescr>sigh</shortdescr>
  <retail>true</retail>
  <imageurl>http://website/sigh.jpg</imageurl>
 </Table>
</NewDataSet>
  1. The [] stuff doesn't refer to parts of the element name, it refers to the position of the element. So the element name is just Table.
  2. You missed the descr and paperid elements.

What the XSLT seems to be doing is laying out items on a list in columns. Yes, it is that ridiculously complicated in XSLT.

Also, it would seem that it's ignoring paperid and paperitemid if imageurl is defined, and ignoring descr if shortdescr is provided. This might help you on your quest.

...how are you supposed to test this without the actual XML, btw?

对你再特殊 2024-09-26 12:53:06

在一般情况下,不可能仅通过 XSLT 确定输入 XML 文件的结构

虽然在这种情况下,您可能能够基于 XSLT 对 XML 描述进行逆向工程,但在一般情况下情况下不可能正确执行。在本例中,这是可能的,因为模板很小并且使用了for-each

XSLT 是声明性的,这意味着您描述了遇到某些节点时应该发生的情况,但包含从未被调用或以不明显的方式调用的模板当然是合法的。类似地,使用 无法了解已知元素内有哪些元素。

例如:

<xsl:template match="book">
    <xhtml:div class="book">
        <xsl:apply-templates />
    </xhtml:div>
</xsl:template>

<xsl:template match="title">
    <xhtml:h1><xsl:value-of select="."/></xhtml:h1>
</xsl:template>

<xsl:template match="chapter/title">
    <xhtml:h2><xsl:value-of select="."/></xhtml:h2>
</xsl:template>

书有标题吗?书有章节吗?章节有标题吗? 我们不知道也不可能知道。

In the general case it is impossible to determine the structure of an input XML file given just an XSLT

While in this instance you may have been able to reverse engineer an XML descprion based on the XSLT, in the generic case its impossible to do correctly. In this instance it was possible because the template was small and used for-each.

XSLT is declarative, which means you describe what should happen if certain nodes are encountered, but its certainly legal to include templates which are never called, or are called in ways that are not obvious. Similarly, the use of <xsl:apply-templates /> gives no insight as to what elements are inside of a know element.

For example:

<xsl:template match="book">
    <xhtml:div class="book">
        <xsl:apply-templates />
    </xhtml:div>
</xsl:template>

<xsl:template match="title">
    <xhtml:h1><xsl:value-of select="."/></xhtml:h1>
</xsl:template>

<xsl:template match="chapter/title">
    <xhtml:h2><xsl:value-of select="."/></xhtml:h2>
</xsl:template>

Does book have a title? Do books have chapters? Do chapters even have titles? We don't and can't know.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文