2017-04-18 9 views
1

필자가 원하는 요소를 만들기 위해 필요한 구문을 고심하는 데 어려움을 겪고 있습니다. XML/XSLT에 대한 새로운 지식과 이것이 올바른 접근 방식인지 확실하지 않습니다.XSLT로 이중 조건을 기반으로 요소 만들기

XML 데이터 파일을 요소 중심으로 구문 분석하여 데이터를 액세스 데이터베이스에서 읽을 수있는 구조로 포맷 할 수 있습니다.

두 조건을 기반으로 요소 내부에서 데이터 값을 가져 오려고합니다.

데이터가 '독서'이라는 요소 안에 있고 데이터의 이름이 '값'입니다. 'Reading'요소 위에 'ConsumptionSpec'이라는 정의 요소가 있습니다.

는 내가 테스트 노력하고있어 측정 단위 (UOM) 현재 'ConsumptionSpec이'에, 그리고 THEN '중 하나의 값을 가지고'TouBucket '라는 이름의 또 다른 속성을 테스트하는 것입니다 TierA ','TierB '/ C/D 또는 합계입니다. UOM은 "kWh, kW, kVAh 또는 kVA"를 보유 할 수 있습니다. 나는 각 Tier (A에서 D까지)와 Total을위한 요소를 만들기 위해이 테스트를 반복 할 예정이므로 첫 번째 레이아웃을 얻으려고합니다. 바로 읽기 위의 ConsumptionSpec를 선택하는-각 다음 XSL을 사용합니다 :이를 테스트 할 때 현재

내가 XSL을 활용하기 위해 노력하고있어 (내가 할 수있는 설명의 명확 제공하기 위해 노력) UOMTouBucket 별도. 테스트가 끝나면 요소를 만들고 현재 요소의 값을 가져 오려고합니다.

다음은 XML에서 발췌 한 내용으로, 테스트 중에 단계별로 수행하려고 시도한 값을 확인할 수 있습니다.

<MeterReadings Irn="Null" Source="Remote" SourceName="Null" SourceIrn="Null" Initiator="Schedule" Purpose="Null" CollectionTime="2017-04-01 09:00:00" > 
    <Meter MeterIrn="Null" MeterName="Null" IsActive="true" SerialNumber="Null" MeterType="A3_ILN" Description="" InstallDate="2017-01-21 05:00:00" RemovalDate="" AccountIdent="Null" AccountName="" SdpIdent="" Location="Null" TimeZoneIndex="Null" Timezone="Null" TimeZoneOffset="300" ObservesDaylightSavings="false" MediaType="900 MHz" /> 

    <ReadingQualityIndicator Name="Tamper Alert" Value="true" /> 

    <ConsumptionData > 

     <ConsumptionSpec UOM="kWh" Direction="Delivered" TouBucket="Total" MeasurementPeriod="Current" Multiplier="1" /> 

     <Reading TimeStamp="2017-04-01 03:08:00" Value="902" /> 

    </ConsumptionData> 

    <ConsumptionData > 

     <ConsumptionSpec UOM="kWh" Direction="Delivered" TouBucket="TierA" MeasurementPeriod="Current" Multiplier="1" /> 

     <Reading TimeStamp="2017-04-01 03:08:00" Value="0" /> 

    </ConsumptionData> 

    <ConsumptionData > 

     <ConsumptionSpec UOM="kWh" Direction="Delivered" TouBucket="TierB" MeasurementPeriod="Current" Multiplier="1" /> 

     <Reading TimeStamp="2017-04-01 03:08:00" Value="0" /> 

    </ConsumptionData> 

    <ConsumptionData > 

     <ConsumptionSpec UOM="kWh" Direction="Delivered" TouBucket="TierC" MeasurementPeriod="Current" Multiplier="1" /> 

     <Reading TimeStamp="2017-04-01 03:08:00" Value="902" /> 

    </ConsumptionData> 

    <ConsumptionData > 

     <ConsumptionSpec UOM="kWh" Direction="Delivered" TouBucket="TierD" MeasurementPeriod="Current" Multiplier="1" /> 

     <Reading TimeStamp="2017-04-01 03:08:00" Value="0" /> 

    </ConsumptionData> 

그리고 여기에 내 현재 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
     <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> 
     <xsl:strip-space elements="*"/> 

     <!-- BY DEFAULT, elements and text nodes are copied, 
      and elements' attributes and contents are transformed as child nodes 
      of the output element --> 
     <xsl:template match="node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
     </xsl:template> 

     <!-- By default, attributes are transformed to elements --> 
     <xsl:template match="@*"> 
     <xsl:element name="{name()}"> 
      <xsl:value-of select="."/> 
     </xsl:element> 
     </xsl:template> 


     <!-- Certain elements have only their contents transformed --> 
     <xsl:template match=" 
      Meter | Status | ConsumptionData | 
      Statuses | MaxDemandData | MaxDemandSpec | 
      InstrumentationValue | IntervalData | IntervalSpec"> 
     <!-- no xsl:copy, and attribute children, if any, are ignored --> 
     <xsl:apply-templates select="@* | node()"/> 
     </xsl:template> 


     <!-- 
     Applies an extra element tag to the selected match 


     and pulls the value from the MeterReading ancestor it's 
     tagged under. 
     --> 

    <xsl:template match="Reading"> 

     <xsl:copy> 

      <xsl:element name="MeterReadingIRN"> 
       <xsl:value-of select="ancestor::MeterReadings/@Irn"/> 
      </xsl:element> 

       <!-- 
       Trying to get into the ConsumptionSpec tag it's related to, 
       then test what the unit of measurement is (UOM), 
       and then test what 'TouBucket' it is a part of (TierA/B/C/D or Total), 
       and THEN create a new element so that I can hold the 'value' that is inside 
       the Reading element, so that it will be referenced to that specific UOM. 
       --> 
      <xsl:for-each select="ancestor::ConsumptionSpec"> 
       <xsl:choose> 
        <xsl:when test="@UOM='kWh'"> 
         <xsl:when test="@TouBucket='Total'"> 

          <xsl:element name="kWhTotal"> 
           <xsl:value-of select="Reading/@Value"/> 
          </xsl:element> 

         </xsl:when> 
        </xsl:when> 
        <!-- Not sure how I can make my otherwise into a useful element here --> 
        <xsl:otherwise> 

         <xsl:element name="BlankTest"> 
          <xsl:value-of select="ancestor::MeterReadings/@Irn"/> 
         </xsl:element> 

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

    <xsl:template match="Channel"> 
    <xsl:copy> 
    <xsl:element name="MeterReadingIRN"> 
    <xsl:value-of select="ancestor::MeterReadings/@Irn"/> 
    </xsl:element> 
    <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

이다 모든 모든 제안은 부활절 주말의 대부분에 대해 내 머리를 두드리는하고, 감사합니다! 더 이해하기 쉽게 제공 할 수있는 정보가 있는지 알려주세요. 대신 당신이 원하는 구문이입니다, 허용되지 않습니다 둥지를 시도 xsl:when 문의

+0

제외 : "특정 요소에는 내용 만 변형되었습니다"라는 주석이 달린 템플릿에는 실제로 일치하는 요소의 특성이 사용자의 의도와는 반대로 변형되어 있습니다. 또한 의도 한 것과 다른 경우에 대비하여 자식 요소뿐만 아니라 텍스트, 주석 및 처리 명령 자식도 변환합니다. –

+0

어쨌든,이 특별한 경우 또는 궁극적으로 다루기를 희망하는보다 일반적인 결과를 얻기 위해 어떤 결과물을 얻길 희망하는지 분명하지 않습니다. 해당 UOM과 TouBucket에서 요소 이름을 동적으로 구성하려고합니까? –

답변

1

... 그러나

<xsl:when test="@UOM='kWh' and @TouBucket='Total'"> 

, 당신은 xsl:for-each의 사용과 함께, 정말 심지어 그 시점 전에 문제가

<xsl:for-each select="ancestor::ConsumptionSpec"> 

는 현재이 시점에서 Reading 요소를 일치하고, 그래서 당신은 현재 해당 요소에 배치됩니다. ConsumptionSpec은 현재 Reading 요소의 조상이 아닙니다. 그것은 형제 다.

<ConsumptionData > 
    <ConsumptionSpec UOM="kWh" Direction="Delivered" TouBucket="TierA" MeasurementPeriod="Current" Multiplier="1" /> 
    <Reading TimeStamp="2017-04-01 03:08:00" Value="0" /> 
</ConsumptionData> 

은 여기 ConsumptionSpecReading 모두의 부모입니다 ConsumptionData이다.

또한 <xsl:for-each select="ancestor::ConsumptionSpec">이 요소를 선택한 경우 Reading에서 ConsumptionSpec으로 사용자의 위치가 변경됩니다.

ReadingConsumptionSpec 만 있다고 가정합니다. 어떤 경우에는 변수를 사용하는 것이 좋습니다. 이 경우 새로운 요소를 만들 xsl:element를 사용하는 실제 필요가 없다,

<xsl:template match="Reading"> 
    <xsl:copy> 
     <MeterReadingIRN> 
      <xsl:value-of select="ancestor::MeterReadings/@Irn"/> 
     </MeterReadingIRN> 
     <xsl:variable name="spec" select="../ConsumptionSpec" /> 
     <xsl:choose> 
      <xsl:when test="$spec/@UOM='kWh' and $spec/@TouBucket='Total'"> 
       <kWhTotal> 
       <xsl:value-of select="@Value"/> 
       </kWhTotal> 
       </xsl:when> 
       <xsl:otherwise> 
       <BlankTest> 
        <xsl:value-of select="ancestor::MeterReadings/@Irn"/> 
       </BlankTest> 
       </xsl:otherwise> 
      </xsl:choose> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

참고 :

대신이 템플릿 경기를 사용해보십시오. 생성하고자하는 요소를 직접 작성하십시오.

는 XPath의 구문 .., 그래서 ../ConsumptionSpecReading 동일한 부모의 자식 인 ConsumptionSpec를 선택한다 부모 선택 수단.

+0

아, 그 부분은 혼란스러워서 조상으로 ConsumptionSpec을 참조하려고 노력했는데, 더 명확하게 내가 일할 수 있었던 것에서 벗어나고 있다고 설명해 주셔서 감사합니다.지금 템플릿을 살펴본 결과, 대단히 감사합니다. –

1

XSL의 반복 및 조건부 요소는 잘 사용되지만 다소 드문 경우입니다. xsl:for-each, xsl:choose 또는 xsl:if 구조를 사용할 때마다 작업을 수행하는 것이 가장 좋은 방법인지 잠시 생각해 봐야합니다.

또한 스타일 시트를 개발할 때 여러 가지를 병렬 케이스로 분할하고 한 번에 하나씩 처리하는 것이 반드시 유리한 것은 아닙니다. XSL은 절차 적 프로그래밍 언어가 아니며 그러한 생각에 도움이되지 않습니다. XSLT는 일종의 전체 론적 인 하향식 접근법 (XML 자체를 연상시키는 방식)에 더 잘 부응하는 경향이 있습니다.

예를 들어 <Reading> 요소 템플릿을 사용하면 공통된 패턴에 맞는 여러 가지 개별 사례에 대한 규칙을 작성하는 것처럼 보입니다. 특히, 해당 ConsumptionSpec의 UOMTouBucket을 기반으로 변형 된 <Reading> 요소의 요소 하위에 동적으로 이름을 지정하려고 시도하는 것 같습니다. 은 무엇이 <xsl:element>에 적합합니다. 리터럴 출력 요소가 제대로 작동하기 때문에 이름이 고정 된 출력 요소에는 실제로 해당 요소가 필요하지 않습니다. 따라서, 당신은 이와 같은 간단한 템플릿 모든 경우를 포함 수 있습니다

<xsl:template match="Reading"> 
    <xsl:copy> 

    <!-- literal output element: --> 
    <MeterReadingIRN> 
     <xsl:value-of select="ancestor::MeterReadings/@Irn"/> 
    </MeterReadingIRN> 

    <xsl:element name="{concat(../ConsumptionSpec/@UOM, ../ConsumptionSpec/@TouBucket)}"> 
     <xsl:value-of select="@Value"/> 
    </xsl:element> 

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

당신이, 당신이 할 수 있도록 스타일 시트를 구조화 고려해야 제공보다 Reading 요소에 대한 변환 사이에 많은 차이를해야 할 경우에도 템플릿에 더 구체적인 match 표현식을 사용하고, 템플릿을 적용 할 노드를 선택하는 데 더 구체적인 select 표현식 및/또는 변형을 표현하고 지시하기위한 다양한 템플릿 모드를 사용하십시오.

+0

사과 어제 사무실에서 전화를 받았는데,이 문제를 다시보고 이해하지 못했습니다. 감사합니다. John. –