XSLT 1.0:优化匹配/逻辑效率以调整超大文档中的文本值

时间:2018-03-03 21:06:27

标签: xml xslt-1.0

我正在使用XSLT 1.0转换以XML格式存储的医疗记录数据。因为这些是患者记录,虽然可以调整某些文本值,但没有任何东西可以删除,所以我必须从身份模板开始。

我需要根据逻辑条件调整某些节点的文本内容,例如包含最多10个不同ID号中的任何一个的另一个兄弟节点。我尝试使用谓词进行过滤,并且,由于它在 XSLT Cookbook 的第4章中提到,我尝试将For-Each应用于其所谓的更快“选择”方法,而不是基于Choose-When逻辑的“过滤”方法。我发现Match与谓词之间的差异和使用For-Each的Select与谓词可以忽略不计。我非常愿意使用Keys,但我不太确定如何应用它来帮助解决我的问题。

我有两个主要问题:

  1. 对于某些设施,我必须评估兄弟节点是否包含大量ID中的任何一个,假设为10.这会使谓词变得笨拙并且可能很慢,如[Item / number ='123'或Item / number ='789'或...... + 10或更多其他可能性]。
  2. 正在处理的一些XML文档非常大。它们可以高达5MB,其中一个我发现15MB。在这种最糟糕的情况下,仅针对我在较大文档中评估的类型的记录,有超过9,000个节点必须被评估或过滤,并且可能被调整。
  3. 至关重要的是,我找到最有效的匹配方式并调整符合条件的节点文本。我们在处理和记录检索时间方面遇到严重延误。如果我能找到一个最佳的解决方案,那么我可以在多个地方重新编写旧的XSLT模板并真正改进。

    我有这样的XML:

    <Facilities>
        <Facility>XYZ</Facility>
        <Records>
            <!--  lots and lots of other kinds of records here A to Z, long XML before this.  -->
            <!--  RecordAAA #1  -->
            <RecordAAA>
                <Item>
                    <number>123</number>
                    <definition>123 really means this</definition>
                </Item>
                <ItemCategory>
                    <ID>AAA</ID>
                    <IdDescription>AAA</IdDescription>
                </ItemCategory>
            </RecordAAA>
            <!--  RecordAAA #2  -->
            <RecordAAA>
                <Item>
                    <number>456</number>
                    <definition>456 really means this</definition>
                </Item>
                <ItemCategory>
                    <ID>AAA</ID>
                    <IdDescription>AAA</IdDescription>
                </ItemCategory>
            </RecordAAA>
            <!--  RecordAAA #3  -->
            <RecordAAA>
                <Item>
                    <number>123</number>
                    <definition>123 really means this</definition>
                </Item>
                <ItemCategory>
                    <ID>AAA</ID>
                    <IdDescription>AAA</IdDescription>
                </ItemCategory>
            </RecordAAA>
            <!--  lots and lots of other kinds of records here A to Z, long XML after this.  -->    
        </Records>
    </Facilities>
    

    所需输出:<ItemCategory> <ID><ItemCategory> <IdDescription>内容根据RecordAAA#2的项目/数字文本为'456'而更改, 而RecordAAA#1和#3只是复制过来:

    <Facilities>
        <Facility>XYZ</Facility>
        <Records>
            <!--  lots and lots of other kinds of records here A to Z, long XML, before this.  -->
            <!--  RecordAAA #1  -->
            <RecordAAA>
                <Item>
                    <number>123</number>
                    <definition>123 really means this</definition>
                </Item>
                <ItemCategory>
                    <ID>AAA</ID>
                    <IdDescription>AAA</IdDescription>
                </ItemCategory>
            </RecordAAA>
            <!--  RecordAAA #2  -->
            <RecordAAA>
                <Item>
                    <number>456</number>
                    <definition>456 really means this</definition>
                </Item>
                <!--  ID and IdDescription have been changed.  -->
                <ItemCategory>
                    <ID>BBB</ID>
                    <IdDescription>BBB</IdDescription>
                </ItemCategory>
            </RecordAAA>
            <!--  RecordAAA #3  -->
            <RecordAAA>
                <Item>
                    <number>123</number>
                    <definition>123 really means this</definition>
                </Item>
                <ItemCategory>
                    <ID>AAA</ID>
                    <IdDescription>AAA</IdDescription>
                </ItemCategory>
            </RecordAAA>
            <!--  lots and lots of other kinds of records here A to Z, long XML, after this.  -->   
        </Records>
    </Facilities>
    

    我有这样的XSLT模板,当然这有效:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <!--  Identity template  -->
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Records/RecordAAA[Item/number='456' or Item/number='789' or Item/number='101112']/ItemCategory">
            <ItemCategory>
                <ID>BBB</ID>
                <IdDescription>BBB</IdDescription>
            </ItemCategory>
        </xsl:template>
    
    </xsl:stylesheet>
    

    但如果我有更多代码的工具,我该怎么办呢?它开始看起来像这样:

    <xsl:template match="Records/RecordAAA[Item/number='456' 
                                                    or Item/number='789' 
                                                    or Item/number='101112'
                                                    or Item/number='1314'
                                                    or Item/number='1516'
                                                    or Item/number='1718'
                                                    or Item/number='1920'
                                                    or Item/number='2122'
                                                    or Item/number='2324'
                                                    or Item/number='2526'
                                                    or Item/number='2728']/ItemCategory">
        <ItemCategory>
            <ID>BBB</ID>
            <IdDescription>BBB</IdDescription>
        </ItemCategory>
    </xsl:template>  
    

    这仍然可以创建所需的输出(就像一系列Choose-When条件一样)但是如何才能更快地完成有没有办法真正提高效率?

    如果对你的答案很重要,我们正在使用Xalan处理器而且我坚持使用版本1.0。

    非常感谢您提供任何可靠的见解。

2 个答案:

答案 0 :(得分:1)

我不确定你能否更快地进行这些比较。

您可以通过在参数或单独文件中保留设施列表来使代码更清晰。

这是一个示例XSL

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

<xsl:param name='facilityfile'>fax.xml</xsl:param>

<xsl:variable name='facility' select='document($facilityfile)//facility/@nbr'/>

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

<!--
<xsl:template match="Records/RecordAAA[Item/number='456' or Item/number='789' or Item/number='101112']/ItemCategory">
-->

<xsl:template match='ItemCategory'>
    <xsl:choose>
        <xsl:when test='preceding-sibling::Item/number=$facility'>
            <ItemCategory>
                <ID>BBB</ID>
                <IdDescription>BBB</IdDescription>
            </ItemCategory>
        </xsl:when>

        <xsl:otherwise>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

和设施fax.xml内容

<xml>
    <facility nbr='456'/>
    <facility nbr='567'/>
    <facility nbr='678'/>
    <facility nbr='789'/>
</xml>

答案 1 :(得分:0)

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="xml" indent="yes"/>

<!-- generate-id(../..) returns the id of the grandparent of number.  ie.   RecordAAA -->
<xsl:key name="myKey" match="number[.='456' or .='789' or .='101112']" use="generate-id(../..)"/>

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

<!-- generate-id(..) returns the parent of ItemCategory.  ie.  RecordAAA-->
<xsl:template match="ItemCategory[key('myKey', generate-id(..))]">
  <ItemCategory>
    <ID>BBB</ID>
    <IdDescription>BBB</IdDescription>
  </ItemCategory>
</xsl:template>

</xsl:stylesheet>