【问题标题】:Compare price in two XML files比较两个 XML 文件中的价格
【发布时间】:2023-03-30 03:41:01
【问题描述】:

我不知道在两个 XML 文件中比较价格变化的最佳方法是什么。

使用 XSLT,我从价目表生成两个(一个实际的,一个较旧的)XML:

newer.xml:

<xml>
  <produkt>
    <code>000161</code>
    <name>Test name</name>
    <available>Yes</available>
    <price>19,90</price>
  </produkt>
</xml>

older.xml

<xml>
  <produkt>
    <code>000161</code>
    <name>Test name</name>
    <available>Yes</available>
    <price>18,90</price>
  </produkt>
</xml>

我尝试用 diff 工具做一个并排比较,但在第二个 XML 中有很多新产品,所以这是不可能的。

也许用 XSLT 生成一个新的 XML 会很好,但这超出了我的知识范围。

  • 产品由&lt;code&gt;标识
  • 检查产品价格是否改变,如果是则复制元素(仅在这种情况下)
  • 不要检查或复制新产品(&lt;code&gt; 不存在于older.xml:不要复制)

比较.xml

<xml>
  <produkt>
    <code>000161</code>
    <name>Test name</name>
    <available>Yes</available>
    <oldprice>18,90</oldprice>
    <newprice>19,90</newprice>
  </produkt>
</xml>

【问题讨论】:

  • 你可以使用 XSLT 2.0 吗?
  • @michael.hor257k 是的,我可以,但是也有 XSLT 1.0 解决方案吗?

标签: xml xslt


【解决方案1】:

older.xml

<?xml version="1.0" encoding="UTF-8"?>
<xml>
    <produkt>
        <code>000160</code>
        <name>Product A (only in old list)</name>
        <available>Yes</available>
        <price>9,90</price>
    </produkt>
    <produkt>
        <code>000161</code>
        <name>Product B (price falls)</name>
        <available>Yes</available>
        <price>19,90</price>
    </produkt>
    <produkt>
        <code>000163</code>
        <name>Product D (price rises)</name>
        <available>Yes</available>
        <price>24,90</price>
    </produkt>
    <produkt>
        <code>000164</code>
        <name>Product E (price unchanged)</name>
        <available>Yes</available>
        <price>99,90</price>
    </produkt>
</xml>

newer.xml

<?xml version="1.0" encoding="UTF-8"?>
<xml>
    <produkt>
        <code>000161</code>
        <name>Product B (price falls)</name>
        <available>Yes</available>
        <price>18,90</price>
    </produkt>
    <produkt>
        <code>000162</code>
        <name>Product C (only in new list)</name>
        <available>Yes</available>
        <price>16,90</price>
    </produkt>
    <produkt>
        <code>000163</code>
        <name>Product D (price rises)</name>
        <available>Yes</available>
        <price>28,90</price>
    </produkt>
    <produkt>
        <code>000164</code>
        <name>Product E (price unchanged)</name>
        <available>Yes</available>
        <price>99,90</price>
    </produkt>
</xml>

比较.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

    <xsl:output indent="yes"/>

    <xsl:template match="xml">
        <xsl:variable name="older" select="document('older.xml')"/>
        <xml>
            <xsl:for-each select="produkt">
                <xsl:variable name="code" select="code"/>
                <xsl:variable name="findProduktByCode" select="$older/xml/produkt[code = $code]"/>
                <xsl:if test="price != $findProduktByCode/price">
                    <produkt>
                        <xsl:copy-of select="code"/>
                        <xsl:copy-of select="name"/>
                        <xsl:copy-of select="available"/>
                        <oldprice>
                            <xsl:value-of select="$findProduktByCode/price"/>
                        </oldprice>
                        <newprice>
                            <xsl:value-of select="price"/>
                        </newprice>
                    </produkt>
                </xsl:if>
            </xsl:for-each>
        </xml>
    </xsl:template>

</xsl:stylesheet>

现在在 newer.xml 上应用 compare.xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xml>
   <produkt>
      <code>000161</code>
      <name>Product B (price falls)</name>
      <available>Yes</available>
      <oldprice>19,90</oldprice>
      <newprice>18,90</newprice>
   </produkt>
   <produkt>
      <code>000163</code>
      <name>Product D (price rises)</name>
      <available>Yes</available>
      <oldprice>24,90</oldprice>
      <newprice>28,90</newprice>
   </produkt>
</xml>

【讨论】:

  • 先生,这是一个五星级的解决方案!
【解决方案2】:

处理交叉引用的简单有效的方法是使用 XSLT 的内置 key 机制:

XSLT 2.0

<xsl:stylesheet version="2.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="path-to-old" select="'older.xml'"/>

<xsl:key name="product-by-code" match="produkt" use="code" />

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

<xsl:template match="produkt">
    <xsl:variable name="old-price" select="key('product-by-code', code, document($path-to-old))/price" />
    <xsl:if test="$old-price != price">
        <xsl:copy>
            <xsl:apply-templates select="@*|node() except price"/>
            <oldprice>
                <xsl:value-of select="$old-price"/>
            </oldprice>
            <newprice>
                <xsl:value-of select="price" />
            </newprice>
        </xsl:copy>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

在 XSLT 1.0 中跨文档应用密钥有点复杂,但仍然可行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多