【问题标题】:Easy way to apply an XSLT to an xml file将 XSLT 应用于 xml 文件的简单方法
【发布时间】:2012-04-18 22:21:30
【问题描述】:

我有一个带有非常神秘标签的 xml 文件结构(它是 HL7 2.3 段名称)。

我知道所有标签在普通英语中的含义。但是每次我必须阅读文件时都查找它们是一件很痛苦的事情。

据我了解,我可以制作一个 XSLT,让我可以查看我的 xml 文件,并以易于阅读的方式对其进行格式化。

一旦我制作了这个 XSLT,有没有一种非常快速和简单的方法可以将它应用到我的 xml 文档中(即从 SQL 或 MSMQ 复制并粘贴它,然后让它自动格式化为 XSLT 定义?

(注意:XML 文件包含我无法以任何方式加载到网络的数据。因此,任何公共托管的网络解决方案都不起作用。)

赏金更新:
为 Maestro13 的答案添加了赏金,修改为匹配 父节点和当前 节点。 (而不仅仅是当前节点。)

由于这首先是 Maestro13 的答案,因此我将奖励赏金给他,而不是其他类似的答案。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    如果你碰巧在 unix 上,有 xsltproc(来自 libxslt 包):

    xsltproc your.xsl your.xml
    

    【讨论】:

    • 谢谢你的回答,可惜我运行的是windows 7
    【解决方案2】:

    我在下面为你写了一个小例子。

    要运行它,您将需要 XML Spy、Oxygen 之类的工具,或者安装 Java JDK 和 Saxon 9HE 并按照 Alp 的说明从命令行运行它。不确定如何在 Saxon 调用或 XSLT 本身中指定翻译文件,但请参阅 Saxon command line syntax;在 Oxygen 或 XML Spy 中,这是在参数列表弹出窗口中完成的。

    输入文件(不是一个真实的例子,只是一个类似于 HL7 的 XML 的提取):

    <?xml version="1.0" encoding="UTF-8"?>
    <ADT_A03>
        <MSH>
            <MSH.7>19900314130405</MSH.7>
        </MSH>
        <EVN>
            <EVN.6>19980327095000</EVN.6>
        </EVN>
        <PID>
            <PID.4.LST>
                <PID.4>
                    <CX.1>123456789ABCDEF</CX.1>
                </PID.4>
            </PID.4.LST>
            <PID.5.LST>
                <PID.5>
                    <XPN.1>PATIENT</XPN.1>
                    <XPN.2>BOB</XPN.2>
                    <XPN.3>S</XPN.3>
                </PID.5>
            </PID.5.LST>
        </PID>
    </ADT_A03>
    

    带有 HL7 标签翻译的附加 XML 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <HL7_translations>
        <MSH description="MessageHeader">
            <MSH.7 description="DateTimeOfMessage"/>
        </MSH>
        <EVN description="EventType">
            <EVN.6 description="EventOccurred"/>
        </EVN>
        <PID description="PatientIdentification">
            <PID.1 description="SetID_PatientID"/>
            <PID.2 description="PatientID_ExternalID"/>
            <PID.3 description="PatientID_InternalID"/>
            <PID.4 description="AlternatePatientID_PID"/>
            <PID.5 description="PatientName"/>
        </PID>
    </HL7_translations>
    

    XSL 转换、读取和处理两个文件(param 是翻译文件;输入源文件是 HL7 XML):

    <?xml version="1.0" encoding="UTF-8"?>
    <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:param name="HL7_translations"/>
    
    <xsl:variable name="doc" select="document($HL7_translations)"/>
    
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*">
        <xsl:variable name="trans" select="$doc//*[name() = name(current())]/@description"/>
        <xsl:copy>
            <xsl:if test="$trans">
                <xsl:attribute name="description"><xsl:value-of select="$trans"/></xsl:attribute>
            </xsl:if>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    输出结果:

    <?xml version="1.0" encoding="UTF-8"?>
    <ADT_A03>
        <MSH description="MessageHeader">
            <MSH.7 description="DateTimeOfMessage">19900314130405</MSH.7>
        </MSH>
        <EVN description="EventType">
            <EVN.6 description="EventOccurred">19980327095000</EVN.6>
        </EVN>
        <PID description="PatientIdentification">
            <PID.4.LST>
                <PID.4 description="AlternatePatientID_PID">
                    <CX.1>123456789ABCDEF</CX.1>
                </PID.4>
            </PID.4.LST>
            <PID.5.LST>
                <PID.5 description="PatientName">
                    <XPN.1>PATIENT</XPN.1>
                    <XPN.2>BOB</XPN.2>
                    <XPN.3>S</XPN.3>
                </PID.5>
            </PID.5.LST>
        </PID>
    </ADT_A03>
    

    在检索描述时编辑以包含父节点

    新的 XML 输入

    <?xml version="1.0" encoding="UTF-8"?>
    <ADT_A03>
        <MSH>
            <MSH.7>19900314130405</MSH.7>
        </MSH>
        <EVN>
            <EVN.6>19980327095000</EVN.6>
        </EVN>
        <PID>
            <PID.4.LST>
                <PID.4>
                    <CX.1>123456789ABCDEF</CX.1>
                </PID.4>
            </PID.4.LST>
            <PID.5.LST>
                <PID.5>
                    <XPN.1>PATIENT</XPN.1>
                    <XPN.2>BOB</XPN.2>
                    <XPN.3>S</XPN.3>
                </PID.5>
            </PID.5.LST>
        </PID>
        <PV1>
            <PV1.7>
                <XCN.1>Attending Doctor's name</XCN.1>
            </PV1.7>
            <PV1.8>
                <XCN.1>Referring Doctor's name</XCN.1>
            </PV1.8>
        </PV1>
        <OBR>
            <OBR.10>
                <XCN.1>Collector Identifier's name</XCN.1>
            </OBR.10>
        </OBR>
    </ADT_A03>
    

    带有描述的新文件(注意添加了中间级别,如 PID.4.LST !)

    <?xml version="1.0" encoding="UTF-8"?>
    <HL7_translations>
        <MSH description="MessageHeader">
            <MSH.7 description="DateTimeOfMessage"/>
        </MSH>
        <EVN description="EventType">
            <EVN.6 description="EventOccurred"/>
        </EVN>
        <PID description="PatientIdentification">
            <PID.1 description="SetID_PatientID"/>
            <PID.2 description="PatientID_ExternalID"/>
            <PID.3 description="PatientID_InternalID"/>
            <PID.4.LST>
                <PID.4 description="AlternatePatientID_PID"/>
            </PID.4.LST>
            <PID.5.LST>
                <PID.5 description="PatientName"/>
            </PID.5.LST>
        </PID>
        <PV1>
            <PV1.7>
                <XCN.1 description="Attending Doctor"/>
            </PV1.7>
            <PV1.8>
                <XCN.1 description="Referring Doctor"/>
            </PV1.8>
        </PV1>
        <OBR>
            <OBR.10>
                <XCN.1 description="Collector Identifier"/>
            </OBR.10>
        </OBR>
    </HL7_translations>
    

    新的 xslt

    <?xml version="1.0" encoding="UTF-8"?>
    <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:param name="HL7_translations"/>
    
    <xsl:variable name="doc" select="document($HL7_translations)"/>
    
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*">
        <xsl:variable name="trans" select="$doc//*[ name() = name(current()) and 
            ( name(current()/..) = name(..) or name(..) = 'HL7_translations')
            ]"/>
        <xsl:copy>
            <xsl:if test="$trans/@description">
                <xsl:attribute name="description"><xsl:value-of select="$trans/@description"/></xsl:attribute>
            </xsl:if>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    所以唯一的变化是

    <xsl:variable name="trans" select="$doc//*[ name() = name(current()) and 
        ( name(current()/..) = name(..) or name(..) = 'HL7_translations')
        ]"/>
    

    另外,我将 /@description 从变量中移出。

    新的输出结果

    <?xml version="1.0" encoding="UTF-8"?>
    <ADT_A03>
        <MSH description="MessageHeader">
            <MSH.7 description="DateTimeOfMessage">19900314130405</MSH.7>
        </MSH>
        <EVN description="EventType">
            <EVN.6 description="EventOccurred">19980327095000</EVN.6>
        </EVN>
        <PID description="PatientIdentification">
            <PID.4.LST>
                <PID.4 description="AlternatePatientID_PID">
                    <CX.1>123456789ABCDEF</CX.1>
                </PID.4>
            </PID.4.LST>
            <PID.5.LST>
                <PID.5 description="PatientName">
                    <XPN.1>PATIENT</XPN.1>
                    <XPN.2>BOB</XPN.2>
                    <XPN.3>S</XPN.3>
                </PID.5>
            </PID.5.LST>
        </PID>
        <PV1>
            <PV1.7>
                <XCN.1 description="Attending Doctor">Attending Doctor's name</XCN.1>
            </PV1.7>
            <PV1.8>
                <XCN.1 description="Referring Doctor">Referring Doctor's name</XCN.1>
            </PV1.8>
        </PV1>
        <OBR>
            <OBR.10>
                <XCN.1 description="Collector Identifier">Collector Identifier's name</XCN.1>
            </OBR.10>
        </OBR>
    </ADT_A03>
    

    【讨论】:

    • 有没有办法使用.net来合并这些?
    • 我在 .NET 中工作。但是,这种方法(虽然非常接近)不太奏效。一些节点名称被重复使用(例如 XCN.1),并且根据使用它的位置,它需要不同的描述。在这个系统中,节点名称在所有 xpath 中都是全局的。 :(关于如何解决这个问题的任何想法?
    • 如果 XCN.1 的父元素对于每个需要不同描述的元素都不同,那么您必须通过在其中包含父元素来更新命名 xpath。我稍后会看看这个并将我的解决方案添加到答案中。
    • 大师,感谢您回到这里。他们每个人的父母都是不同的。每个节点(有描述)都有一个父节点。并且父节点和节点的组合是唯一的。
    • 仅供参考,我为此更改添加了赏金。
    【解决方案3】:

    您可以通过 Saxon's XSLT processor 做到这一点。

    java -jar saxon9he.jar -xsl:your_transformation_file.xsl -s:your_source_input.xml -o:your_transformed_output.xml
    

    【讨论】:

      【解决方案4】:

      使用描述检索的单独答案,包括父节点名称(为了您的方便)

      新的 XML 输入

      <?xml version="1.0" encoding="UTF-8"?>
      <ADT_A03>
          <MSH>
              <MSH.7>19900314130405</MSH.7>
          </MSH>
          <EVN>
              <EVN.6>19980327095000</EVN.6>
          </EVN>
          <PID>
              <PID.4.LST>
                  <PID.4>
                      <CX.1>123456789ABCDEF</CX.1>
                  </PID.4>
              </PID.4.LST>
              <PID.5.LST>
                  <PID.5>
                      <XPN.1>PATIENT</XPN.1>
                      <XPN.2>BOB</XPN.2>
                      <XPN.3>S</XPN.3>
                  </PID.5>
              </PID.5.LST>
          </PID>
          <PV1>
              <PV1.7>
                  <XCN.1>Attending Doctor's name</XCN.1>
              </PV1.7>
              <PV1.8>
                  <XCN.1>Referring Doctor's name</XCN.1>
              </PV1.8>
          </PV1>
          <OBR>
              <OBR.10>
                  <XCN.1>Collector Identifier's name</XCN.1>
              </OBR.10>
          </OBR>
      </ADT_A03>
      

      带有描述的新文件(注意添加了中间级别,如 PID.4.LST !)

      <?xml version="1.0" encoding="UTF-8"?>
      <HL7_translations>
          <MSH description="MessageHeader">
              <MSH.7 description="DateTimeOfMessage"/>
          </MSH>
          <EVN description="EventType">
              <EVN.6 description="EventOccurred"/>
          </EVN>
          <PID description="PatientIdentification">
              <PID.1 description="SetID_PatientID"/>
              <PID.2 description="PatientID_ExternalID"/>
              <PID.3 description="PatientID_InternalID"/>
              <PID.4.LST>
                  <PID.4 description="AlternatePatientID_PID"/>
              </PID.4.LST>
              <PID.5.LST>
                  <PID.5 description="PatientName"/>
              </PID.5.LST>
          </PID>
          <PV1>
              <PV1.7>
                  <XCN.1 description="Attending Doctor"/>
              </PV1.7>
              <PV1.8>
                  <XCN.1 description="Referring Doctor"/>
              </PV1.8>
          </PV1>
          <OBR>
              <OBR.10>
                  <XCN.1 description="Collector Identifier"/>
              </OBR.10>
          </OBR>
      </HL7_translations>
      

      新的 xslt

      <?xml version="1.0" encoding="UTF-8"?>
      <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:param name="HL7_translations"/>
      
      <xsl:variable name="doc" select="document($HL7_translations)"/>
      
      <xsl:template match="/">
          <xsl:apply-templates/>
      </xsl:template>
      
      <xsl:template match="@*|node()">
          <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
      </xsl:template>
      
      <xsl:template match="*">
          <xsl:variable name="trans" select="$doc//*[ name() = name(current()) and 
              ( name(current()/..) = name(..) or .. = .//*[1])
              ]"/>
          <xsl:copy>
              <xsl:if test="$trans/@description">
                  <xsl:attribute name="description"><xsl:value-of select="$trans/@description"/></xsl:attribute>
              </xsl:if>
              <xsl:apply-templates/>
          </xsl:copy>
      </xsl:template>
      
      </xsl:stylesheet>
      

      所以唯一的变化是

      <xsl:variable name="trans" select="$doc//*[ name() = name(current()) and 
          ( name(current()/..) = name(..) or .. = .//*[1])
          ]"/>
      

      另外,我将 /@description 从变量中移出。

      新的输出结果

      <?xml version="1.0" encoding="UTF-8"?>
      <ADT_A03>
          <MSH description="MessageHeader">
              <MSH.7 description="DateTimeOfMessage">19900314130405</MSH.7>
          </MSH>
          <EVN description="EventType">
              <EVN.6 description="EventOccurred">19980327095000</EVN.6>
          </EVN>
          <PID description="PatientIdentification">
              <PID.4.LST>
                  <PID.4 description="AlternatePatientID_PID">
                      <CX.1>123456789ABCDEF</CX.1>
                  </PID.4>
              </PID.4.LST>
              <PID.5.LST>
                  <PID.5 description="PatientName">
                      <XPN.1>PATIENT</XPN.1>
                      <XPN.2>BOB</XPN.2>
                      <XPN.3>S</XPN.3>
                  </PID.5>
              </PID.5.LST>
          </PID>
          <PV1>
              <PV1.7>
                  <XCN.1 description="Attending Doctor">Attending Doctor's name</XCN.1>
              </PV1.7>
              <PV1.8>
                  <XCN.1 description="Referring Doctor">Referring Doctor's name</XCN.1>
              </PV1.8>
          </PV1>
          <OBR>
              <OBR.10>
                  <XCN.1 description="Collector Identifier">Collector Identifier's name</XCN.1>
              </OBR.10>
          </OBR>
      </ADT_A03>
      

      【讨论】:

      • 这很完美!太感谢了。只需等待 11 小时即可获得赏金。 (所以不会让我早点这样做。)
      • 没问题 - 很高兴能提供帮助!而且我在途中学到了一点 HL7 :-)
      • @Vaccano 注意:一个微小的改进可能是不依赖于 or name(..) = 'HL7_translations' 中翻译根元素名称的固定文字值,而是使用如下通用检查:or .. = .//*[1](翻译to '父元素是文档中的第一个元素')。
      • 谢谢,这确实有很大帮助。 (我有几个翻译文档,它们都有不同的根名称。再次感谢您的帮助!
      猜你喜欢
      • 2010-12-03
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-12
      • 2012-09-28
      相关资源
      最近更新 更多