구조화된 데이터 형식의 일부 출력이 있는데 이를 XML로 변환해야 합니다.
내 사용 사례는 Palo Alto 방화벽이 구성을 복원하는 데 사용할 수 없는 명령줄 인터페이스를 통해 구성 출력을 제공한다는 것입니다. 사용하기 전에 XML로 변환해야 합니다.
형식은 다음과 같습니다(아이디어를 이해하기 위한 더 큰 파일의 일부).
unknown-applications {
unknown-tcp {
destinations-per-hour 10;
sessions-per-hour 10;
session-length {
maximum-bytes 100;
minimum-bytes 50;
}
}
unknown-udp {
destinations-per-hour 10;
sessions-per-hour 10;
session-length {
maximum-bytes 100;
minimum-bytes 50;
}
}
}
그리고 필요하다
<unknown-applications>
<unknown-tcp>
<destinations-per-hour>10</destinations-per-hour>
<sessions-per-hour>10</sessions-per-hour>
<session-length>
<maximum-bytes>100</maximum-bytes>
<minimum-bytes>50</minimum-bytes>
</session-length>
</unknown-tcp>
<unknown-udp>
<destinations-per-hour>10</destinations-per-hour>
<sessions-per-hour>10</sessions-per-hour>
<session-length>
<maximum-bytes>100</maximum-bytes>
<minimum-bytes>50</minimum-bytes>
</session-length>
</unknown-udp>
</unknown-applications>
이를 달성할 수 있는 파서와 같은 것이 있습니까?
편집: 댓글 때문에 이렇게 많이 게시할 수 없기 때문에: 감사합니다. 유망해 보입니다!
예시를 나열하지 않았기 때문에 일부 부품이 올바르게 변환되지 않았습니다.
import {
network {
interface [ ethernet1/5 ethernet1/6];
}
}
로 변환됩니다
<import>
<network>
<interface>[</interface>
</network>
</import>
하지만 그래야 해
<import>
<network>
<interface>
<member>ethernet1/5</member>
<member>ethernet1/6</member>
</interface>
</network>
</import>
회원으로 만들기 위해 []와 같은 몇 가지 특정 사항이 있으므로 수동으로 수행하는 것이 가능한지 잘 모르겠습니다... 원시 형식도 xml 형식이어야 합니다.
답변1
입력 형식이 비표준이므로 이를 처리하려면 파서를 작성해야 합니다. 두 가지 접근 방식이 있습니다. 절차적 프로그래밍 언어(일반적으로 하향식 재귀 하강 파서)로 "직접" 작성하거나 일종의 파서 생성기를 사용할 수 있습니다. 후자의 접근 방식에서는 입력 문법의 BNF를 정의하고 도구가 파서를 구축합니다. Scala를 사용하는 방법을 안다면 매우 쉽습니다.
XML 세계에서 자주 사용되는 또 다른 파서 생성기는 REx입니다. 이는 XQuery 또는 XSLT에서 파서를 생성하므로 문제의 XML 생성 측면을 매우 쉽게 만들어 주기 때문에 편리합니다. 이것은 훌륭한 소프트웨어이지만 불행하게도 관련 문서가 부족합니다. . 또 다른 XML 지향 도구는 Stephen Pemberton의 "Invisible XML"(https://homepages.cwi.nl/~steven/ixml/) - REx가 훌륭한 소프트웨어이지만 문서화가 부족하다면 불행하게도 Invisible XML은 문서화는 훌륭하지만 많이 출시된 소프트웨어는 아닙니다.
저는 또 다른 저렴하고 재미있는 방법을 생각했습니다. 정규식을 기반으로 하는 매우 간단한 편집기 스크립트를 사용하면 다음을 수행할 수 있습니다.
- 이름을 따옴표로 묶고 종료 콜론을 추가하세요.
- 세미콜론을 쉼표로 바꾸기
그런 다음 많은 JSON 파서가 허용하는 것을 얻습니다(세미콜론이 구분 기호가 아닌 종결자이기 때문에 이는 청구서에 맞지 않지만 많은 JSON 파서가 이를 허용합니다.)
답변2
awk
다음은 데이터가 표시된 것과 정확히 같다고 가정하는 간단한 프로그램입니다 .
- 선행 "태그"는
{
태그만 포함하는 줄에 있고, - 데이터가 있는 행에는 정확히 하나의 레이블이 포함되고 그 뒤에 단어와
;
, - 각각은
}
다른 내용 없이 한 줄에 나타납니다.
스택을 사용하여 현재 사용 중인 태그를 추적하고 새 태그가 입력에 표시되면 스택에 푸시합니다. a 가 발견되면 }
스택 상단의 끝 마커가 출력됩니다. 데이터 라인은 {
단일 문자로 끝나지 않는다는 사실 로 감지됩니다 }
.
어떤 방식으로든 데이터의 유효성을 검증하려는 시도가 이루어지지 않았습니다.
$NF == "{" {
stack[++top] = $1 # push tag to stack
printf "<%s>\n", stack[top] # output opening tag
next
}
$NF == "}" {
printf "</%s>\n", stack[top--] # output closing tag + pop stack
next
}
{
sub(";$", "", $2) # remove ; from EOL
printf "<%s>%s</%s>\n", $1, $2, $1 # output tag with data
}
예제 데이터의 경우 awk -f script.awk data.in
수율
<unknown-applications>
<unknown-tcp>
<destinations-per-hour>10</destinations-per-hour>
<sessions-per-hour>10</sessions-per-hour>
<session-length>
<maximum-bytes>100</maximum-bytes>
<minimum-bytes>50</minimum-bytes>
</session-length>
</unknown-tcp>
<unknown-udp>
<destinations-per-hour>10</destinations-per-hour>
<sessions-per-hour>10</sessions-per-hour>
<session-length>
<maximum-bytes>100</maximum-bytes>
<minimum-bytes>50</minimum-bytes>
</session-length>
</unknown-udp>
</unknown-applications>
실행 xmlstarlet fo
하면
<?xml version="1.0"?>
<unknown-applications>
<unknown-tcp>
<destinations-per-hour>10</destinations-per-hour>
<sessions-per-hour>10</sessions-per-hour>
<session-length>
<maximum-bytes>100</maximum-bytes>
<minimum-bytes>50</minimum-bytes>
</session-length>
</unknown-tcp>
<unknown-udp>
<destinations-per-hour>10</destinations-per-hour>
<sessions-per-hour>10</sessions-per-hour>
<session-length>
<maximum-bytes>100</maximum-bytes>
<minimum-bytes>50</minimum-bytes>
</session-length>
</unknown-udp>
</unknown-applications>