2013-07-02 3 views
2

모든 속성의 개행 문자를 대체 문자로 바꾸려면 XSLT (또는 무언가 - 아래 참조)가 필요합니다.XML 속성의 개행 문자를 XSLT로 바꾸기

모든 데이터를 특성으로 저장하고 새 줄을 사용하여 카디널리티를 표현하는 레거시 XML을 처리해야합니다. 예를 들어 : 그래서이 문제가되지 않습니다 내가합니다 (XML 사양에 따라) 자바에서 파일을 구문 분석 할 때이 새로운 라인은 공백으로 대체되고있다

<sample> 
    <p att="John 
    Paul 
    Ringo"></p> 
</sample> 

그러나 나는리스트로 처리하고자하고 특히 유용합니다.

내 '솔루션'은 XSLT를 사용하여 모든 속성의 모든 개행 문자를 다른 구분 기호로 대체하는 것이었지만 XSLT에 대한 지식은 전혀 없습니다. 지금까지 본 모든 예제는 매우 구체적이거나 속성 값 대신 노드 내용을 대체했습니다.

저는 XSLT 2.0의 replace()으로 손을 씻었지만 모든 것을 정리하는 데 어려움을 겪고 있습니다.

XSLT가 올바른 해결책입니까? 아래의 XSLT로 :

샘플 XML에 적용

<xsl:template match="sample/*"> 
    <xsl:for-each select="@*"> 
     <xsl:value-of select="replace(current(), '\n', '|')"/> 
    </xsl:for-each> 
</xsl:template> 
다음 사용 색슨를 출력합니다

John Paul Ringo 

분명히이 형식이 아닌 어떤 난 후 -이 replace() 실험 단지입니다 - 하지만 XSLT 처리가 완료 될 때까지 이미 정규화되었습니다. 그렇다면 Java 파서를 사용하여 이러한 값을 쓰기로 구문 분석하는 다른 방법이 있습니까? 지금까지 JAXB 만 사용했습니다.

+0

필자는 고무 장갑을 착용하고 파싱하기 전에 XML 문자열에 더러운 정규식을 구현해야하는 매우 불쾌한 느낌을 가지고 있습니다. 불행히도 XML을 생성 할 수있는 권한이 없습니다. – nullPainter

+0

사실, 그렇게 생각하기에는 너무 무섭습니다. – nullPainter

+0

속성 값 내의 공백이 의미 상으로 중요하다면 XML을 다루지 않으므로 비 XML 도구를 사용해야합니다. [Per spec] (http://www.w3.org/TR/xml/#AVNormalize) 속성 값 내의 모든 개행은 파서가 공백으로 변환 할 수 있으며, 표시되는 값에 개행 문자가 필요한 경우 구문 분석 후 문자 참조 (' ')로 이스케이프 처리해야합니다. –

답변

1

JSoup (XML이 아닌 도구로 XML 구문 분석에 대한 @Ian Roberts의 의견에 동의하지 않음)으로 XML을 사전 처리하여이 문제를 해결했습니다. JSoup는 HTML 문서 용으로 설계되었지만이 컨텍스트에서 잘 작동합니다. 다음과 같이

내 코드는 다음과 같습니다 내 질문에 샘플 XML에 대한

@Test 
public void verifyNewlineEscaping() { 
    final List<Node> nodes = Parser.parseXmlFragment(FileUtils.readFileToString(sourcePath.toFile(), "UTF-8"), ""); 

    fixAttributeNewlines(nodes); 

    // Reconstruct XML 
    StringBuilder output = new StringBuilder(); 
    for (Node node : nodes) { 
     output.append(node.toString()); 
    } 

    // Print cleansed output to stdout 
    System.out.println(output); 
} 

/** 
* Replace newlines and surrounding whitespace in XML attributes with an alternative delimiter in 
* order to avoid whitespace normalisation converting newlines to a single space. 
* 
* <p> 
* This is useful if newlines which have semantic value have been incorrectly inserted into 
* attribute values. 
* </p> 
* 
* @param nodes nodes to update 
*/ 
private static void fixAttributeNewlines(final List<Node> nodes) { 

    /* 
    * Recursively iterate over all attributes in all nodes in the XML document, performing 
    * attribute string replacement 
    */ 
    for (final Node node : nodes) { 
     final List<Attribute> attributes = node.attributes().asList(); 

     for (final Attribute attribute : attributes) { 

      // JSoup reports whitespace as attributes 
      if (!StringUtils.isWhitespace(attribute.getValue())) { 
       attribute.setValue(attribute.getValue().replaceAll("\\s*\r?\n\\s*", "|")); 
      } 
     } 

     // Recursively process child nodes 
     if (!node.childNodes().isEmpty()) { 
      fixAttributeNewlines(node.childNodes()); 
     } 
    } 
} 

,이 방법의 출력은 : 나는 &#10;를 사용하고 있지 않다

<sample> 
    <p att="John|Paul|Ringo"></p> 
</sample> 

참고 JSoup 오히려 때문에 그것의 특성에서 경계하고 도주한다 모두 속성 값에서.또한 기존의 숫자 엔터티 참조를 UTF-8에 해당하는 것으로 바꿉니다. 따라서 시간이 지나칠 수없는 솔루션인지 여부를 알 수 있습니다.

+1

JSoup 사용의 단점은 현재 속성 이름을 소문자로 변환한다는 점입니다. 이것을 상세히 기술 한 [열린 버그] (https://github.com/jhy/jsoup/issues/272)가 있습니다. – nullPainter

2

이렇게하는 것이 어려워 보입니다. Are line breaks in XML attribute values allowed?에서 알 수 있듯이 속성의 줄 바꿈 문자는 유효하지만 XML 파서는 정규화 (https://stackoverflow.com/a/8188290/1324394)하므로 처리하기 전에 (따라서 바꾸기 전에) 손실 될 수 있습니다.

+0

나는 그것도 보았다. 그러나 나는 그들이 여전히 XSLT 픽스 업을 위해있을 수 있기를 희망했다. 나는 이후 XML 스펙을 따르지 않아도되는 XML 파서가 아니라고 주장함으로써이 문제를 극복 한 http://jdom.org/을 발견했다. 이제 총을 내고 ... – nullPainter

+0

큰 소리로 생각하면 다음과 같이 할 수 있습니다. 'replace (/ data/@ value,'\ s {2,10} ','| ')'- 절대적으로 아닙니다. newline 대신 하나 이상의 공간이 필요하지만 작업을 할 수 있기 때문에 정확합니다. –

+0

@ JirkaŠ. XML 파서는 데이터가 XPath 데이터 모델까지 도달하기 전에 속성 값의 모든 연속 공백을 하나의 공백으로 축소하기 때문에 작동하지 않습니다. –

0

XSLT는 특성 값 정규화를 수행 한 XML 구문 분석기에서 XML을 처리 한 후에 만 ​​XML을 확인합니다.

일부 XML 파서에는 속성 값 정규화를 억제하는 옵션이 있다고 생각합니다. 그러한 파서에 액세스 할 수 없다면 구문 분석을하기 전에 &#x0A;에 의해 (\ r? \ n)을 텍스트로 바꾸는 것이 최선의 탈출 경로 일 수 있다고 생각합니다. 이런 식으로 이스케이프 된 개행 문자는 속성 값 정규화로 인해 표시되지 않습니다.

+0

마이클에게 감사드립니다. 합리적인 양의 파기를 한 후에는 속성 값 정규화를 억제 할 수있는 Java 기반 파서를 찾으려는 공백을 생각해냅니다. 필자가 제작중인 XML을 제어 할 수 없으므로 텍스트 대체가 어렵습니다. 즉, 대체 값을 속성 값으로 제한 할 수 없습니다. – nullPainter

관련 문제